mirror of
https://git.wownero.com/lza_menace/suchwow.git
synced 2024-08-15 01:03:19 +00:00
add moderator support and approval workflow
This commit is contained in:
parent
91219f4309
commit
d7bc4f4546
7 changed files with 93 additions and 28 deletions
|
@ -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…
Reference in a new issue