From d7bc4f454668f516eddb58574645098559da8230 Mon Sep 17 00:00:00 2001 From: lza_menace Date: Thu, 3 Dec 2020 23:17:58 -0800 Subject: [PATCH] add moderator support and approval workflow --- suchwow/app.py | 36 +++++++++++++++++++++++++++----- suchwow/models.py | 8 +++++++ suchwow/routes/post.py | 25 +++++++++++++++++----- suchwow/templates/index.html | 3 ++- suchwow/templates/post/read.html | 17 +++------------ suchwow/utils/decorators.py | 17 +++++++++++++-- suchwow/utils/helpers.py | 15 ++++++++++++- 7 files changed, 93 insertions(+), 28 deletions(-) diff --git a/suchwow/app.py b/suchwow/app.py index 46a326d..c91a053 100644 --- a/suchwow/app.py +++ b/suchwow/app.py @@ -7,9 +7,9 @@ from flask import Flask, request, session, redirect from flask import render_template, flash, url_for from flask_session import Session 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.utils.decorators import login_required +from suchwow.utils.decorators import login_required, moderator_required from suchwow.reddit import make_post from suchwow.discord import post_discord_webhook from suchwow import wownero @@ -37,13 +37,19 @@ def index(): flash("Wow, wtf hackerman. Cool it.") page = 1 - posts = Post.select().order_by(Post.timestamp.desc()) + posts = Post.select().where(Post.approved==True).order_by(Post.timestamp.desc()) if submitter: posts = posts.where(Post.submitter == submitter) posts = posts.paginate(page, itp) total_pages = Post.select().count() / itp 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") def about(): return render_template("about.html") @@ -60,7 +66,7 @@ def init(): makedirs(f"{config.DATA_FOLDER}/{i}", exist_ok=True) # init db - db.create_tables([Post, Profile, Comment, Notification]) + db.create_tables([Post, Profile, Comment, Notification, Moderator]) @app.cli.command("create_accounts") def create_accounts(): @@ -106,7 +112,7 @@ def payout_users(): @app.cli.command("delete_post") @click.argument("post_id") -def delete_post(post_id): +def _delete_post(post_id): post = Post.get(id=post_id) save_path_base = path.join(app.config["DATA_FOLDER"], "uploads") save_path = path.join(save_path_base, post.image_name) @@ -114,5 +120,25 @@ def delete_post(post_id): remove(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__": app.run() diff --git a/suchwow/models.py b/suchwow/models.py index 3fb6b91..ab5493d 100644 --- a/suchwow/models.py +++ b/suchwow/models.py @@ -19,6 +19,14 @@ class Post(Model): reddit_url = CharField(null=True) to_reddit = 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: database = db diff --git a/suchwow/routes/post.py b/suchwow/routes/post.py index 53a6c1b..aab11fc 100644 --- a/suchwow/routes/post.py +++ b/suchwow/routes/post.py @@ -6,8 +6,8 @@ from secrets import token_urlsafe from suchwow import wownero from suchwow import config from suchwow.models import Post, Comment -from suchwow.utils.decorators import login_required, profile_required -from suchwow.utils.helpers import allowed_file +from suchwow.utils.decorators import login_required, profile_required, moderator_required +from suchwow.utils.helpers import allowed_file, is_moderator, get_session_user bp = Blueprint("post", "post") @@ -15,7 +15,7 @@ bp = Blueprint("post", "post") @bp.route("/posts/top") def top(): top_posts = {} - posts = Post.select() + posts = Post.select().where(Post.approved==True) for post in posts: transfers = [] incoming = wownero.Wallet().incoming_transfers(post.account_index) @@ -32,7 +32,10 @@ def read(id): if Post.filter(id=id): wallet = wownero.Wallet() 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: address = wallet.get_address(account=post.account_index) transfers = wallet.transfers(account=post.account_index) @@ -43,7 +46,6 @@ def read(id): "post/read.html", post=post, address=address, - comments=comments, transfers=transfers ) else: @@ -101,6 +103,19 @@ def create(): return redirect(url_for("post.read", id=post.id)) return render_template("post/create.html") +@bp.route("/post//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//delete") @login_required def delete(id): diff --git a/suchwow/templates/index.html b/suchwow/templates/index.html index fcb7325..77d20c2 100644 --- a/suchwow/templates/index.html +++ b/suchwow/templates/index.html @@ -30,7 +30,7 @@ {% endif %} - +{% if page %} {% if page > 1 %} Back {% endif %} @@ -38,6 +38,7 @@ {% if page < total_pages and total_pages > 0 %} Next {% endif %} +{% endif %}

Leaderboards

diff --git a/suchwow/templates/post/read.html b/suchwow/templates/post/read.html index e0540cc..b95da16 100644 --- a/suchwow/templates/post/read.html +++ b/suchwow/templates/post/read.html @@ -12,6 +12,9 @@

{{ post.title }}

{{ post.text }}

+ {% if not post.approved %} + + {% endif %}

Submitted by {{ post.submitter }} at {{ post.timestamp }}


@@ -42,22 +45,8 @@ {% endif %}
- -

Comments

- {% if comments %} - {% for comment in comments %} -

- #{{ comment.id }} - {{ comment.commenter.username }} - {{ comment.comment }} -

- {% endfor %} - {% else %} -

No comments yet.

- {% endif %} - {% endif %} - - {# {% if "auth" in session %} {% if session.auth.preferred_username == post.submitter %} diff --git a/suchwow/utils/decorators.py b/suchwow/utils/decorators.py index f244370..e2380d6 100644 --- a/suchwow/utils/decorators.py +++ b/suchwow/utils/decorators.py @@ -1,6 +1,6 @@ -from flask import session, redirect, url_for +from flask import session, redirect, url_for, flash from functools import wraps -from suchwow.models import Profile +from suchwow.models import Profile, Moderator def login_required(f): @@ -11,6 +11,19 @@ def login_required(f): return f(*args, **kwargs) 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): @wraps(f) def decorated_function(*args, **kwargs): diff --git a/suchwow/utils/helpers.py b/suchwow/utils/helpers.py index 74a4aea..edbff4e 100644 --- a/suchwow/utils/helpers.py +++ b/suchwow/utils/helpers.py @@ -1,6 +1,19 @@ -from flask import current_app +from flask import current_app, session +from suchwow.models import Moderator def allowed_file(filename): return "." in filename and \ 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"]