From 3fa904df647c48c3bfe301d6917b218810986d14 Mon Sep 17 00:00:00 2001 From: lza_menace Date: Mon, 3 Jan 2022 01:27:28 -0800 Subject: [PATCH] setting up remote server capabilities --- .../92b2ce4b6c87_add_remote_servers.py | 35 ++++++++++++ suchwowx/cli/cli.py | 54 ++++++++++++++++++- suchwowx/filters.py | 2 + suchwowx/helpers.py | 3 +- suchwowx/models.py | 13 +++++ suchwowx/routes/meme.py | 3 -- suchwowx/routes/meta.py | 42 ++++++++++++++- suchwowx/templates/includes/navbar.html | 7 +++ suchwowx/templates/publish.html | 19 +++---- suchwowx/templates/remotes.html | 34 ++++++++++++ 10 files changed, 192 insertions(+), 20 deletions(-) create mode 100644 alembic/versions/92b2ce4b6c87_add_remote_servers.py create mode 100644 suchwowx/templates/remotes.html diff --git a/alembic/versions/92b2ce4b6c87_add_remote_servers.py b/alembic/versions/92b2ce4b6c87_add_remote_servers.py new file mode 100644 index 0000000..655c388 --- /dev/null +++ b/alembic/versions/92b2ce4b6c87_add_remote_servers.py @@ -0,0 +1,35 @@ +"""add remote servers + +Revision ID: 92b2ce4b6c87 +Revises: f6f695a38339 +Create Date: 2022-01-03 01:20:39.066496 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '92b2ce4b6c87' +down_revision = 'f6f695a38339' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('remotes', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('create_date', sa.DateTime(), nullable=True), + sa.Column('last_sync_date', sa.DateTime(), nullable=True), + sa.Column('paused', sa.Boolean(), nullable=True), + sa.Column('endpoint', sa.String(length=120), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('remotes') + # ### end Alembic commands ### diff --git a/suchwowx/cli/cli.py b/suchwowx/cli/cli.py index 2ca52d1..b8d23ae 100644 --- a/suchwowx/cli/cli.py +++ b/suchwowx/cli/cli.py @@ -4,7 +4,7 @@ from secrets import token_urlsafe from suchwowx.factory import db from suchwowx.helpers import get_eth_contract -from suchwowx.models import Meme, User +from suchwowx.models import Meme, User, Remote from suchwowx import config @@ -72,3 +72,55 @@ def sync_avax(): print(f'[+] Added new meme {meme.id}') except Exception as e: print(e) + + +# @bp.cli.command('sync-remotes') +# def sync_remotes(): +# """ +# Sync remote servers with local database. +# """ +# remotes = Remote.query.filter(Remote.paused == False) +# for remote in remotes: +# deets = request.get(remote.endpoint + '/api/v1/memes').json() +# meme_exists = Meme.query.filter(Meme.meta_ipfs_hash == deets['meta_ipfs_hash']).first() # noqa +# user_exists = User.query.filter(User.public_address == deets[4].lower()).first() # noqa +# if meme_exists: +# if not meme_exists.minted: +# meme_exists.minted = True +# db.session.commit() +# print(f'[+] Marked existing meme {meme_exists.id} as minted') +# else: +# print(deets) +# if not user_exists: +# user_exists = User( +# public_address=deets[4].lower() +# ) +# db.session.add(user_exists) +# db.session.commit() +# user_exists.handle = f'anon{user_exists.id}-{token_urlsafe(6)}' +# db.session.commit() +# print(f'[+] Created user {user_exists.handle}') +# res = requests.get(f'{config.IPFS_SERVER}/ipfs/{deets[5]}', timeout=30).json() +# if not 'image' in res: +# print('No image IPFS hash, skipping') +# continue +# meme_ipfs_hash = res['image'].split('ipfs://')[1] +# filename = token_urlsafe(24) +# print(f'[+] Downloading image hash {meme_ipfs_hash} as {filename}') +# r = requests.get(f'{config.IPFS_SERVER}/ipfs/{meme_ipfs_hash}', stream=True) +# with open(f'{config.DATA_FOLDER}/uploads/{filename}', 'wb') as f: +# for chunk in r.iter_content(chunk_size = 16*1024): +# f.write(chunk) +# meme = Meme( +# title=res['name'], +# file_name=filename, +# description=res['description'], +# user_id=user_exists.id, +# meta_ipfs_hash=deets[5], +# meme_ipfs_hash=meme_ipfs_hash, +# minted=True, +# synced=True +# ) +# db.session.add(meme) +# db.session.commit() +# print(f'[+] Added new meme {meme.id}') diff --git a/suchwowx/filters.py b/suchwowx/filters.py index fe18e92..1be4450 100644 --- a/suchwowx/filters.py +++ b/suchwowx/filters.py @@ -16,6 +16,8 @@ def shorten_address(a): @bp.app_template_filter('humanize') def humanize(d): + if not d: + return 'never' return arrow_get(d).humanize() @bp.app_template_filter() diff --git a/suchwowx/helpers.py b/suchwowx/helpers.py index 8b268dc..0502236 100644 --- a/suchwowx/helpers.py +++ b/suchwowx/helpers.py @@ -33,9 +33,8 @@ def upload_to_ipfs(meme_id: str): if not meme: return False try: - full_path = f'{config.DATA_FOLDER}/uploads/{meme.file_name}' client = ipfsApi.Client('127.0.0.1', 5001) - artwork_hashes = client.add(full_path) + artwork_hashes = client.add(meme.get_fs_path()) artwork_hash = artwork_hashes[0]['Hash'] print(f'[+] Uploaded artwork to IPFS: {artwork_hash}') meta = { diff --git a/suchwowx/models.py b/suchwowx/models.py index 8eefec7..44fa732 100644 --- a/suchwowx/models.py +++ b/suchwowx/models.py @@ -117,3 +117,16 @@ class Meme(db.Model): def get_fs_path(self): return f'{config.DATA_FOLDER}/uploads/{self.file_name}' + + +class Remote(db.Model): + __tablename__ = 'remotes' + + id = db.Column(db.Integer, primary_key=True) + create_date = db.Column(db.DateTime, default=datetime.utcnow) + last_sync_date = db.Column(db.DateTime, nullable=True) + paused = db.Column(db.Boolean, default=False) + endpoint = db.Column(db.String(120)) + + def __repr__(self): + return str(f'remote-{self.id}') diff --git a/suchwowx/routes/meme.py b/suchwowx/routes/meme.py index 7bceaee..a2f9281 100644 --- a/suchwowx/routes/meme.py +++ b/suchwowx/routes/meme.py @@ -44,7 +44,6 @@ def publish(): flash('You need to connect your wallet first.', 'warning') return redirect(url_for('meme.index')) meme = None - form_err = False try: client = ipfsApi.Client('127.0.0.1', 5001) client.add_json({}) @@ -56,8 +55,6 @@ def publish(): return '' return redirect(url_for('meme.index') + '?ipfs_error=1') if "file" in request.files: - if form_err: - return '' title = request.form.get('title') description = request.form.get('description') file = request.files["file"] diff --git a/suchwowx/routes/meta.py b/suchwowx/routes/meta.py index ffd6755..b9f2361 100644 --- a/suchwowx/routes/meta.py +++ b/suchwowx/routes/meta.py @@ -1,7 +1,9 @@ from flask import Blueprint, render_template, send_from_directory -from flask import redirect, url_for -from flask_login import logout_user +from flask import redirect, url_for, flash, request +from flask_login import logout_user, current_user +from suchwowx.models import User, Remote +from suchwowx.factory import db from suchwowx import config @@ -25,3 +27,39 @@ def about(): def disconnect(): logout_user() return redirect(url_for('meme.index')) + + +@bp.route('/remotes', methods=['GET', 'POST']) +def remotes(): + if not current_user.is_authenticated or not current_user.is_moderator(): + flash('You need to be moderator to access that page.', 'warning') + return redirect(url_for('meme.index')) + remotes = Remote.query.filter().order_by(Remote.create_date.asc()) + ep = request.form.get('endpoint') + if ep: + if ep.startswith('http'): + if not Remote.query.filter(Remote.endpoint == ep).first(): + r = Remote(endpoint=ep) + db.session.add(r) + db.session.commit() + flash('Added new remote server.', 'success') + else: + flash('That remote server already exists.', 'warning') + else: + flash('Incorrect endpoint provided, must start with http or https', 'warning') # noqa + return render_template('remotes.html', remotes=remotes) + + +@bp.route('/remotes/delete/') +def delete_remote(remote_id): + existing = Remote.query.get(remote_id) + if not current_user.is_authenticated or not current_user.is_moderator(): + flash('You need to be moderator to access that page.', 'warning') + return redirect(url_for('meme.index')) + if not existing: + flash('That remote does not exist', 'warning') + return redirect(url_for('meme.mod')) + db.session.delete(existing) + db.session.commit() + flash(f'Deleted remote server {existing}', 'success') + return redirect(url_for('meta.remotes')) diff --git a/suchwowx/templates/includes/navbar.html b/suchwowx/templates/includes/navbar.html index d9af146..3858db2 100644 --- a/suchwowx/templates/includes/navbar.html +++ b/suchwowx/templates/includes/navbar.html @@ -20,4 +20,11 @@ {% else %} Go Home {% endif %} + + {% if request.path == '/remotes' %} + Mod + {% endif %} + {% if request.path == '/mod' %} + Remotes + {% endif %} diff --git a/suchwowx/templates/publish.html b/suchwowx/templates/publish.html index 40221f2..dff0c46 100644 --- a/suchwowx/templates/publish.html +++ b/suchwowx/templates/publish.html @@ -4,14 +4,9 @@
-

- SuchWowX. -

-

- Memes. Interplanetary! -

- Go Back + {% include 'includes/navbar.html' %} +
@@ -21,16 +16,16 @@
- +
- +

{{ current_user.public_address }}

- +
-

{{ current_user.public_address }}

+
@@ -56,7 +51,7 @@
- +
diff --git a/suchwowx/templates/remotes.html b/suchwowx/templates/remotes.html new file mode 100644 index 0000000..30adea1 --- /dev/null +++ b/suchwowx/templates/remotes.html @@ -0,0 +1,34 @@ + + + {% include 'includes/head.html' %} + +
+
+ {% include 'includes/navbar.html' %} + +
+
+
+ +
+ +
+
+
+
+ +
+
+
+ {% if remotes %} +
+ {% for remote in remotes %} +

{{ remote.endpoint }} - last synced: {{ remote.last_sync_date | humanize }} x

+ {% endfor %} + {% endif %} +
+
+
+ {% include 'includes/footer.html' %} + +