add moderator support and approval workflow

master
lza_menace 4 years ago
parent 91219f4309
commit d7bc4f4546

@ -7,9 +7,9 @@ from flask import Flask, request, session, redirect
from flask import render_template, flash, url_for from flask import render_template, flash, url_for
from flask_session import Session from flask_session import Session
from suchwow import config from suchwow import config
from suchwow.models import Post, Profile, Comment, Notification, db from suchwow.models import Post, Profile, Comment, Notification, db, Moderator
from suchwow.routes import auth, comment, post, profile, leaderboard from suchwow.routes import auth, comment, post, profile, leaderboard
from suchwow.utils.decorators import login_required from suchwow.utils.decorators import login_required, moderator_required
from suchwow.reddit import make_post from suchwow.reddit import make_post
from suchwow.discord import post_discord_webhook from suchwow.discord import post_discord_webhook
from suchwow import wownero from suchwow import wownero
@ -37,13 +37,19 @@ def index():
flash("Wow, wtf hackerman. Cool it.") flash("Wow, wtf hackerman. Cool it.")
page = 1 page = 1
posts = Post.select().order_by(Post.timestamp.desc()) posts = Post.select().where(Post.approved==True).order_by(Post.timestamp.desc())
if submitter: if submitter:
posts = posts.where(Post.submitter == submitter) posts = posts.where(Post.submitter == submitter)
posts = posts.paginate(page, itp) posts = posts.paginate(page, itp)
total_pages = Post.select().count() / itp total_pages = Post.select().count() / itp
return render_template("index.html", posts=posts, page=page, total_pages=total_pages) return render_template("index.html", posts=posts, page=page, total_pages=total_pages)
@app.route("/mod")
@moderator_required
def mod_queue():
posts = Post.select().where(Post.approved==False).order_by(Post.timestamp.asc())
return render_template("index.html", posts=posts)
@app.route("/about") @app.route("/about")
def about(): def about():
return render_template("about.html") return render_template("about.html")
@ -60,7 +66,7 @@ def init():
makedirs(f"{config.DATA_FOLDER}/{i}", exist_ok=True) makedirs(f"{config.DATA_FOLDER}/{i}", exist_ok=True)
# init db # init db
db.create_tables([Post, Profile, Comment, Notification]) db.create_tables([Post, Profile, Comment, Notification, Moderator])
@app.cli.command("create_accounts") @app.cli.command("create_accounts")
def create_accounts(): def create_accounts():
@ -106,7 +112,7 @@ def payout_users():
@app.cli.command("delete_post") @app.cli.command("delete_post")
@click.argument("post_id") @click.argument("post_id")
def delete_post(post_id): def _delete_post(post_id):
post = Post.get(id=post_id) post = Post.get(id=post_id)
save_path_base = path.join(app.config["DATA_FOLDER"], "uploads") save_path_base = path.join(app.config["DATA_FOLDER"], "uploads")
save_path = path.join(save_path_base, post.image_name) save_path = path.join(save_path_base, post.image_name)
@ -114,5 +120,25 @@ def delete_post(post_id):
remove(save_path) remove(save_path)
print(f"Deleted post {post_id} and image {save_path}") print(f"Deleted post {post_id} and image {save_path}")
@app.cli.command("add_admin")
@click.argument("username")
def add_admin(username):
if not Moderator.filter(username=username):
m = Moderator(username=username)
m.save()
print(f"Added {username}")
else:
print("That moderator already exists")
@app.cli.command("remove_admin")
@click.argument("username")
def add_admin(username):
m = Moderator.filter(username=username).first()
if m:
m.delete_instance()
print(f"Deleted {username}")
else:
print("That moderator doesn't exist")
if __name__ == "__main__": if __name__ == "__main__":
app.run() app.run()

@ -19,6 +19,14 @@ class Post(Model):
reddit_url = CharField(null=True) reddit_url = CharField(null=True)
to_reddit = BooleanField(default=False) to_reddit = BooleanField(default=False)
to_discord = BooleanField(default=False) to_discord = BooleanField(default=False)
approved = BooleanField(default=False)
class Meta:
database = db
class Moderator(Model):
id = AutoField()
username = CharField(unique=True)
class Meta: class Meta:
database = db database = db

@ -6,8 +6,8 @@ from secrets import token_urlsafe
from suchwow import wownero from suchwow import wownero
from suchwow import config from suchwow import config
from suchwow.models import Post, Comment from suchwow.models import Post, Comment
from suchwow.utils.decorators import login_required, profile_required from suchwow.utils.decorators import login_required, profile_required, moderator_required
from suchwow.utils.helpers import allowed_file from suchwow.utils.helpers import allowed_file, is_moderator, get_session_user
bp = Blueprint("post", "post") bp = Blueprint("post", "post")
@ -15,7 +15,7 @@ bp = Blueprint("post", "post")
@bp.route("/posts/top") @bp.route("/posts/top")
def top(): def top():
top_posts = {} top_posts = {}
posts = Post.select() posts = Post.select().where(Post.approved==True)
for post in posts: for post in posts:
transfers = [] transfers = []
incoming = wownero.Wallet().incoming_transfers(post.account_index) incoming = wownero.Wallet().incoming_transfers(post.account_index)
@ -32,7 +32,10 @@ def read(id):
if Post.filter(id=id): if Post.filter(id=id):
wallet = wownero.Wallet() wallet = wownero.Wallet()
post = Post.get(id=id) post = Post.get(id=id)
comments = Comment.select().where(Comment.post==post.id) if not post.approved:
if not is_moderator(get_session_user()):
flash("That post has not been approved.")
return redirect("/")
if wallet.connected: if wallet.connected:
address = wallet.get_address(account=post.account_index) address = wallet.get_address(account=post.account_index)
transfers = wallet.transfers(account=post.account_index) transfers = wallet.transfers(account=post.account_index)
@ -43,7 +46,6 @@ def read(id):
"post/read.html", "post/read.html",
post=post, post=post,
address=address, address=address,
comments=comments,
transfers=transfers transfers=transfers
) )
else: else:
@ -101,6 +103,19 @@ def create():
return redirect(url_for("post.read", id=post.id)) return redirect(url_for("post.read", id=post.id))
return render_template("post/create.html") return render_template("post/create.html")
@bp.route("/post/<id>/approve")
@moderator_required
def approve(id):
post = Post.get(id=id)
if post:
post.approved = True
post.save()
flash("Approved")
return redirect(url_for("mod_queue"))
else:
flash("You can't approve this")
return redirect(url_for("index"))
@bp.route("/post/<id>/delete") @bp.route("/post/<id>/delete")
@login_required @login_required
def delete(id): def delete(id):

@ -30,7 +30,7 @@
{% endif %} {% endif %}
{% if page %}
{% if page > 1 %} {% if page > 1 %}
<a href="{% if request.args.submitter %}/?submitter={{ request.args.submitter }}&{% else %}/?{% endif %}page={{ page - 1 }}" style="padding:1em;">Back</a> <a href="{% if request.args.submitter %}/?submitter={{ request.args.submitter }}&{% else %}/?{% endif %}page={{ page - 1 }}" style="padding:1em;">Back</a>
{% endif %} {% endif %}
@ -38,6 +38,7 @@
{% if page < total_pages and total_pages > 0 %} {% if page < total_pages and total_pages > 0 %}
<a href="{% if request.args.submitter %}/?submitter={{ request.args.submitter }}&{% else %}/?{% endif %}page={{ page + 1 }}" style="padding:1em;">Next</a> <a href="{% if request.args.submitter %}/?submitter={{ request.args.submitter }}&{% else %}/?{% endif %}page={{ page + 1 }}" style="padding:1em;">Next</a>
{% endif %} {% endif %}
{% endif %}
<hr> <hr>
<h3>Leaderboards</h3> <h3>Leaderboards</h3>

@ -12,6 +12,9 @@
<!-- Post Info --> <!-- Post Info -->
<h1>{{ post.title }}</h1> <h1>{{ post.title }}</h1>
<p class="subtitle">{{ post.text }}</p> <p class="subtitle">{{ post.text }}</p>
{% if not post.approved %}
<a href="{{ url_for('post.approve', id=post.id) }}"><button type="button" name="button">Approve</button></a>
{% endif %}
<p class="subtext">Submitted by <i><u><a href="/?submitter={{ post.submitter }}">{{ post.submitter }}</a></u></i> at <i>{{ post.timestamp }}</i></p> <p class="subtext">Submitted by <i><u><a href="/?submitter={{ post.submitter }}">{{ post.submitter }}</a></u></i> at <i>{{ post.timestamp }}</i></p>
<br> <br>
<img src="{{ url_for('post.uploaded_file', filename=post.image_name) }}" width=600/ style="margin-bottom:1em;border-radius:4px;"> <img src="{{ url_for('post.uploaded_file', filename=post.image_name) }}" width=600/ style="margin-bottom:1em;border-radius:4px;">
@ -42,22 +45,8 @@
{% endif %} {% endif %}
<hr> <hr>
<!-- Comments -->
<h2>Comments</h2>
{% if comments %}
{% for comment in comments %}
<p id="comment{{ comment.id }}" class="comment">
<a href="{{ url_for('post.read', id=post.id, _external=True) }}#comment{{ comment.id }}">#{{ comment.id }}</a> - <i>{{ comment.commenter.username }}</i> - {{ comment.comment }}
</p>
{% endfor %}
{% else %}
<p>No comments yet.</p>
{% endif %}
{% endif %} {% endif %}
<a href="{{ url_for('comment.create', post_id=post.id) }}"><button class="btn btn-warning">Leave a Comment</button></a>
{# {#
{% if "auth" in session %} {% if "auth" in session %}
{% if session.auth.preferred_username == post.submitter %} {% if session.auth.preferred_username == post.submitter %}

@ -1,6 +1,6 @@
from flask import session, redirect, url_for from flask import session, redirect, url_for, flash
from functools import wraps from functools import wraps
from suchwow.models import Profile from suchwow.models import Profile, Moderator
def login_required(f): def login_required(f):
@ -11,6 +11,19 @@ def login_required(f):
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
def moderator_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if "auth" not in session or not session["auth"]:
return redirect(url_for("auth.login"))
m = Moderator.filter(username=session["auth"]["preferred_username"])
if m:
return f(*args, **kwargs)
else:
flash("You are not a moderator")
return redirect(url_for("index"))
return decorated_function
def profile_required(f): def profile_required(f):
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):

@ -1,6 +1,19 @@
from flask import current_app from flask import current_app, session
from suchwow.models import Moderator
def allowed_file(filename): def allowed_file(filename):
return "." in filename and \ return "." in filename and \
filename.rsplit(".", 1)[1].lower() in current_app.config["ALLOWED_EXTENSIONS"] filename.rsplit(".", 1)[1].lower() in current_app.config["ALLOWED_EXTENSIONS"]
def is_moderator(username):
m = Moderator.filter(username=username)
if m:
return True
else:
return False
def get_session_user():
if "auth" not in session or not session["auth"]:
return None
return session["auth"]["preferred_username"]

Loading…
Cancel
Save