updating mod queue, adding more routes for mods

main
lza_menace 3 years ago
parent ba76f9e5bb
commit 0c91a1be3d

@ -1,6 +1,9 @@
import ipfsApi
from eth_account.messages import encode_defunct from eth_account.messages import encode_defunct
from suchwowx.factory import w3 from suchwowx.models import Meme
from suchwowx.factory import w3, db
from suchwowx import config
def verify_signature(message, signature, public_address): def verify_signature(message, signature, public_address):
@ -10,3 +13,28 @@ def verify_signature(message, signature, public_address):
return True return True
else: else:
return False return False
def upload_to_ipfs(meme_id: str):
meme = Meme.query.get(meme_id)
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_hash = artwork_hashes[0]['Hash']
print(f'[+] Uploaded artwork to IPFS: {artwork_hash}')
meta = {
'name': meme.title,
'description': meme.description,
'image': f'ipfs://{artwork_hash}',
'by': meme.creator_handle,
'properties': {
'creator': meme.creator_handle
}
}
meta_hash = client.add_json(meta)
print(f'[+] Uploaded metadata to IPFS: {meta_hash}')
return (meta_hash, artwork_hash)
except Exception as e:
return False

@ -99,3 +99,6 @@ class Meme(db.Model):
def __repr__(self): def __repr__(self):
return str(f'meme-{self.id}') return str(f'meme-{self.id}')
def get_fs_path(self):
return f'{config.DATA_FOLDER}/uploads/{self.file_name}'

@ -1,4 +1,4 @@
from os import path from os import path, remove
from secrets import token_urlsafe from secrets import token_urlsafe
from json import loads, dumps from json import loads, dumps
@ -10,6 +10,7 @@ from requests.exceptions import HTTPError
from web3 import Web3 from web3 import Web3
from suchwowx.models import Meme, User from suchwowx.models import Meme, User
from suchwowx.helpers import upload_to_ipfs
from suchwowx.factory import db from suchwowx.factory import db
from suchwowx import config from suchwowx import config
@ -36,8 +37,8 @@ def mod():
return redirect(url_for('meme.index')) return redirect(url_for('meme.index'))
memes = Meme.query.filter( memes = Meme.query.filter(
Meme.meta_ipfs_hash == None Meme.meta_ipfs_hash == None
).order_by(Meme.create_date.desc()) ).order_by(Meme.create_date.asc())
return render_template('review.html', memes=memes) return render_template('mod.html', memes=memes)
@bp.route('/publish', methods=['GET', 'POST']) @bp.route('/publish', methods=['GET', 'POST'])
def publish(): def publish():
@ -55,7 +56,7 @@ def publish():
flash(msg, 'error') flash(msg, 'error')
if "file" in request.files: if "file" in request.files:
return '<script>window.history.back()</script>' return '<script>window.history.back()</script>'
return redirect(url_for('meme.index')) return redirect(url_for('meme.index') + '?ipfs_error=1')
if "file" in request.files: if "file" in request.files:
if form_err: if form_err:
return '<script>window.history.back()</script>' return '<script>window.history.back()</script>'
@ -70,38 +71,22 @@ def publish():
full_path = f'{config.DATA_FOLDER}/uploads/{filename}' full_path = f'{config.DATA_FOLDER}/uploads/{filename}'
file.save(full_path) file.save(full_path)
try: try:
meta_hash = None
artwork_hash = None
if current_user.verified or current_user.is_moderator():
client = ipfsApi.Client('127.0.0.1', 5001)
artwork_hashes = client.add(full_path)
print(artwork_hashes)
artwork_hash = artwork_hashes[0]['Hash']
print(artwork_hash)
print(f'[+] Uploaded artwork to IPFS: {artwork_hash}')
meta = {
'name': title,
'description': description,
'image': f'ipfs://{artwork_hash}',
'by': creator,
'properties': {
'creator': creator
}
}
meta_hash = client.add_json(meta)
print(f'[+] Uploaded metadata to IPFS: {meta_hash}')
flash('Published new meme to IPFS', 'success')
meme = Meme( meme = Meme(
file_name=filename, file_name=filename,
meta_ipfs_hash=meta_hash,
meme_ipfs_hash=artwork_hash,
title=title, title=title,
description=description, description=description,
creator_handle=creator creator_handle=creator
) )
db.session.add(meme) db.session.add(meme)
db.session.commit() db.session.commit()
flash('Published new meme to database', 'success') if current_user.verified or current_user.is_moderator():
res = upload_to_ipfs(meme.id)
meme.meta_ipfs_hash = res[0]
meme.meme_ipfs_hash = res[1]
db.session.commit()
flash('Published new meme to local database and IPFS.', 'success')
else:
flash('Published new meme to database for review by moderators.', 'success')
return redirect(url_for('meme.index')) return redirect(url_for('meme.index'))
except ConnectionError: except ConnectionError:
flash('[!] Unable to connect to local ipfs', 'error') flash('[!] Unable to connect to local ipfs', 'error')
@ -112,16 +97,56 @@ def publish():
meme=meme meme=meme
) )
@bp.route('/meme/<meme_id>') @bp.route('/meme/<meme_id>')
def meme(meme_id): def show(meme_id):
meme = Meme.query.filter(Meme.id == meme_id).first() meme = Meme.query.filter(Meme.id == meme_id).first()
if not meme: if not meme:
return redirect('/') return redirect('/')
if not meme.meta_ipfs_hash and not current_user.is_authenticated: if not meme.meta_ipfs_hash and not current_user.is_authenticated:
flash('You need to be a moderator to view that meme', 'warning') flash('You need to be a moderator to view that meme.', 'warning')
return redirect(url_for('meme.index')) return redirect(url_for('meme.index'))
elif not meme.meta_ipfs_hash and not current_user.is_moderator(): elif not meme.meta_ipfs_hash and not current_user.is_moderator():
flash('You need to be a moderator to view that meme', 'warning') flash('You need to be a moderator to view that meme.', 'warning')
return redirect(url_for('meme.index')) return redirect(url_for('meme.index'))
return render_template('meme.html', meme=meme) return render_template('meme.html', meme=meme)
@bp.route('/meme/<meme_id>/<action>')
def approve(meme_id, action):
if not current_user.is_authenticated:
flash('You need to be logged in to reach this page.', 'warning')
return redirect(url_for('meme.index'))
if not current_user.is_moderator():
flash('You need to be a moderator to reach this page.', 'warning')
return redirect(url_for('meme.index'))
meme = Meme.query.get(meme_id)
if not meme:
flash('That meme does not exist.', 'warning')
return redirect(url_for('meme.index'))
if meme.meta_ipfs_hash != None:
flash('That meme already has been published to IPFS.', 'warning')
return redirect(url_for('meme.show', meme_id=meme.id))
if action == 'approve':
res = upload_to_ipfs(meme.id)
if not res:
flash('Unable to post to IPFS, daemon may be offline.', 'error')
return redirect(url_for('meme.show', meme_id=meme.id))
existing_meta_ipfs = Meme.query.filter(Meme.meta_ipfs_hash == res[0]).first()
existing_meme_ipfs = Meme.query.filter(Meme.meme_ipfs_hash == res[1]).first()
if existing_meta_ipfs or existing_meme_ipfs:
flash('Cannot use an existing IPFS hash for either metadata or memes.', 'warning')
return redirect(url_for('meme.show', meme_id=meme.id))
meme.meta_ipfs_hash = res[0]
meme.meme_ipfs_hash = res[1]
db.session.commit()
flash('Published new meme to IPFS.', 'success')
elif action == 'deny':
# delete image
# delete from database
if path.exists(meme.get_fs_path()):
remove(meme.get_fs_path())
db.session.delete(meme)
db.session.commit()
flash('Deleted image and removed meme from database.', 'success')
else:
flash('Unknown action.', 'warning')
return redirect(url_for('meme.mod'))

@ -6,16 +6,14 @@
<div class="container"> <div class="container">
{% include 'includes/navbar.html' %} {% include 'includes/navbar.html' %}
{% if get_flashed_messages(with_categories=true) %} {% if request.args.get('ipfs_error') %}
<div class="screen"> <div class="screen">
<p> <p>
You can run your own local IPFS instance and maintain metadata and artwork, You can run your own local IPFS instance and maintain metadata and artwork,
</br>
try installing the software and running the following: try installing the software and running the following:
</p> </p>
<code>$ ipfs daemon</code> <code>$ ipfs daemon</code>
</div> </div>
</br></br>
{% endif %} {% endif %}
{% if memes %} {% if memes %}
@ -26,7 +24,7 @@
<div class="card"> <div class="card">
<div class="card-image"> <div class="card-image">
<figure class="image"> <figure class="image">
<a href="{{ url_for('meme.meme', meme_id=meme.id) }}" up-preload up-follow=".container"> <a href="{{ url_for('meme.show', meme_id=meme.id) }}" up-preload up-follow=".container">
{% if meme.file_name.endswith('mp4') %} {% if meme.file_name.endswith('mp4') %}
<video class="img-fluid" {% if not request.MOBILE %}autoplay{% else %}controls{% endif %} muted loop> <video class="img-fluid" {% if not request.MOBILE %}autoplay{% else %}controls{% endif %} muted loop>
<source src="{{ url_for('meta.uploaded_file', filename=meme.file_name) }}" type="video/mp4"> <source src="{{ url_for('meta.uploaded_file', filename=meme.file_name) }}" type="video/mp4">

@ -38,12 +38,23 @@
<p>Meme IPFS: <a href="{{ meme_url }}" target=_self up-preload up-follow=".container">{{ meme.meme_ipfs_hash }}</a></p> <p>Meme IPFS: <a href="{{ meme_url }}" target=_self up-preload up-follow=".container">{{ meme.meme_ipfs_hash }}</a></p>
{% endif %} {% endif %}
<p>Meme ID: <code>{{ meme }}</code></p> <p>Meme ID: <code>{{ meme }}</code></p>
{% if not meme.meta_ipfs_hash %}
</br>
<div class="columns">
<div class="column">
<a class="button is-info is-12 column" href="{{ url_for('meme.approve', meme_id=meme.id, action='approve') }}">Approve</a>
</div>
<div class="column">
<a class="button is-danger is-12 column" href="{{ url_for('meme.approve', meme_id=meme.id, action='deny') }}">Deny</a>
</div>
</div>
{% endif %}
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</section> </section>
{% include 'includes/footer.html' %}
</body> </body>
</html> </html>

@ -14,7 +14,7 @@
<div class="card"> <div class="card">
<div class="card-image"> <div class="card-image">
<figure class="image"> <figure class="image">
<a href="{{ url_for('meme.meme', meme_id=meme.id) }}" up-preload up-follow=".container"> <a href="{{ url_for('meme.show', meme_id=meme.id) }}" up-preload up-follow=".container">
{% if meme.file_name.endswith('mp4') %} {% if meme.file_name.endswith('mp4') %}
<video class="img-fluid" {% if not request.MOBILE %}autoplay{% else %}controls{% endif %} muted loop> <video class="img-fluid" {% if not request.MOBILE %}autoplay{% else %}controls{% endif %} muted loop>
<source src="{{ url_for('meta.uploaded_file', filename=meme.file_name) }}" type="video/mp4"> <source src="{{ url_for('meta.uploaded_file', filename=meme.file_name) }}" type="video/mp4">
Loading…
Cancel
Save