aboutsummaryrefslogtreecommitdiffhomepage
path: root/apioforum/forum.py
diff options
context:
space:
mode:
Diffstat (limited to 'apioforum/forum.py')
-rw-r--r--apioforum/forum.py194
1 files changed, 87 insertions, 107 deletions
diff --git a/apioforum/forum.py b/apioforum/forum.py
index 988c9a5..f88900f 100644
--- a/apioforum/forum.py
+++ b/apioforum/forum.py
@@ -8,6 +8,7 @@ from flask import (
)
from .db import get_db
+from .orm import DBObj
from .mdrender import render
from .roles import get_forum_roles,has_permission,is_bureaucrat,get_user_role, permissions as role_permissions
from .permissions import is_admin
@@ -16,6 +17,15 @@ import datetime
import math
import functools
+class Forum(DBObj,table="forums"):
+ fields = ["id","name","parent","description","unlisted"]
+
+ def avail_tags(self):
+ db = get_db()
+ tags = db.execute("select * from tags where forum = ?",(self.id,)).fetchall()
+ return tags
+
+
THREADS_PER_PAGE = 35
bp = Blueprint("forum", __name__, url_prefix="/")
@@ -24,30 +34,6 @@ bp = Blueprint("forum", __name__, url_prefix="/")
def not_actual_index():
return redirect("/1")
-def get_avail_tags(forum_id):
- db = get_db()
- tags = db.execute("""
- WITH RECURSIVE fs AS
- (SELECT * FROM forums WHERE id = ?
- UNION ALL
- SELECT forums.* FROM forums, fs WHERE fs.parent=forums.id)
- SELECT * FROM tags
- WHERE tags.forum in (SELECT id FROM fs)
- ORDER BY id;
- """,(forum_id,)).fetchall()
- return tags
-
-def forum_path(forum_id):
- db = get_db()
- ancestors = db.execute("""
- WITH RECURSIVE fs AS
- (SELECT * FROM forums WHERE id = ?
- UNION ALL
- SELECT forums.* FROM forums, fs WHERE fs.parent=forums.id)
- SELECT * FROM fs;
- """,(forum_id,)).fetchall()
- ancestors.reverse()
- return ancestors
def forum_route(relative_path, pagination=False, **kwargs):
def decorator(f):
@@ -58,9 +44,7 @@ def forum_route(relative_path, pagination=False, **kwargs):
@bp.route(path, **kwargs)
@functools.wraps(f)
def wrapper(forum_id, *args, **kwargs):
- db = get_db()
- forum = db.execute("SELECT * FROM forums WHERE id = ?",
- (forum_id,)).fetchone()
+ forum = Forum.fetch(id=forum_id)
if forum == None:
abort(404)
return f(forum, *args, **kwargs)
@@ -74,7 +58,7 @@ def requires_permission(permission, login_required=True):
def decorator(f):
@functools.wraps(f)
def wrapper(forum, *args, **kwargs):
- if not has_permission(forum['id'],g.user,permission,login_required):
+ if not has_permission(forum.id,g.user,permission,login_required):
abort(403)
return f(forum, *args, **kwargs)
return wrapper
@@ -84,7 +68,7 @@ def requires_bureaucrat(f):
@functools.wraps(f)
@requires_permission("p_view_forum")
def wrapper(forum, *args, **kwargs):
- if not is_bureaucrat(forum['id'], g.user):
+ if not is_bureaucrat(forum.id, g.user):
abort(403)
return f(forum, *args, **kwargs)
return wrapper
@@ -102,9 +86,9 @@ def view_forum(forum,page=1):
sortby_dir = {'d':'DESC','a':'ASC'}[sortby[1]]
sortby_by = {'a':'threads.updated','c':'threads.created'}[sortby[0]]
except KeyError:
- return redirect(url_for('forum.view_forum',forum_id=forum['id']))
+ return redirect(url_for('forum.view_forum',forum_id=forum.id))
- avail_tags = get_avail_tags(forum['id'])
+ avail_tags = forum.avail_tags()
tagfilter = request.args.get("tagfilter",None)
if tagfilter == "":
@@ -116,7 +100,7 @@ def view_forum(forum,page=1):
tagfilter = int(tagfilter)
except ValueError:
flash(f'invalid tag id "{tagfilter}"')
- return redirect(url_for('forum.view_forum',forum_id=forum['id']))
+ abort(400)
else:
# there is no risk of sql injection because
# we just checked it is an int
@@ -127,7 +111,7 @@ def view_forum(forum,page=1):
break
else:
flash("that tag doesn't exist or isn't available here")
- return redirect(url_for('forum.view_forum',forum_id=forum['id']))
+ abort(400)
threads = db.execute(
@@ -148,7 +132,7 @@ def view_forum(forum,page=1):
ORDER BY {sortby_by} {sortby_dir}
LIMIT ? OFFSET ?;
""",(
- forum['id'],
+ forum.id,
THREADS_PER_PAGE,
(page-1)*THREADS_PER_PAGE,
)).fetchall()
@@ -157,15 +141,13 @@ def view_forum(forum,page=1):
SELECT count(*) AS count FROM threads
LEFT OUTER JOIN thread_tags ON threads.id = thread_tags.thread
WHERE threads.forum = ? {tagfilter_clause};
- """,(forum['id'],)).fetchone()['count']
+ """,(forum.id,)).fetchone()['count']
max_pageno = math.ceil(num_threads/THREADS_PER_PAGE)
thread_tags = {}
thread_polls = {}
-
- #todo: somehow optimise this
for thread in threads:
thread_tags[thread['id']] = db.execute(
"""SELECT tags.* FROM tags
@@ -197,13 +179,17 @@ def view_forum(forum,page=1):
thread_polls[thread['id']]=poll
- subforums_rows = db.execute("""
- SELECT max(threads.updated) as updated, forums.* FROM forums
- LEFT OUTER JOIN threads ON threads.forum=forums.id
- WHERE parent = ? AND unlisted = 0
- GROUP BY forums.id
- ORDER BY name ASC
- """,(forum['id'],)).fetchall()
+ # subforums don't exist any more
+ # forums will be able to link to other forums though, eventually
+ #
+ subforums_rows = []
+ # subforums_rows = db.execute("""
+ # SELECT max(threads.updated) as updated, forums.* FROM forums
+ # LEFT OUTER JOIN threads ON threads.forum=forums.id
+ # WHERE parent = ? AND unlisted = 0
+ # GROUP BY forums.id
+ # ORDER BY name ASC
+ # """,(forum.id,)).fetchall()
subforums = []
for s in subforums_rows:
a={}
@@ -216,7 +202,7 @@ def view_forum(forum,page=1):
bureaucrats = db.execute("""
SELECT user FROM role_assignments
WHERE role = 'bureaucrat' AND forum = ?
- """,(forum['id'],)).fetchall()
+ """,(forum.id,)).fetchall()
bureaucrats = [b[0] for b in bureaucrats]
return render_template("view_forum.html",
@@ -226,7 +212,6 @@ def view_forum(forum,page=1):
thread_tags=thread_tags,
bureaucrats=bureaucrats,
thread_polls=thread_polls,
- avail_tags=avail_tags,
max_pageno=max_pageno,
page=page,
current_sortby=sortby,
@@ -238,43 +223,38 @@ def view_forum(forum,page=1):
@requires_permission("p_view_forum")
def create_thread(forum):
db = get_db()
- forum = db.execute("SELECT * FROM forums WHERE id = ?",(forum['id'],)).fetchone()
- if forum is None:
- flash("that forum doesn't exist")
- return redirect(url_for('index'))
+
+ # i want to immortalize this
+ #forum = db.execute("SELECT * FROM forums WHERE id = ?",(forum.id,)).fetchone()
+
if g.user is None:
- flash("you need to be logged in to create a thread")
- return redirect(url_for('index'))
+ abort(403,"you need to be logged in to create a thread")
if request.method == "POST":
title = request.form['title']
content = request.form['content']
- err = None
if len(title.strip()) == 0 or len(content.strip()) == 0:
- err = "title and content can't be empty"
-
- if err is None:
- cur = db.cursor()
- cur.execute(
- "INSERT INTO threads (title,creator,created,updated,forum) VALUES (?,?,current_timestamp,current_timestamp,?);",
- (title,g.user,forum['id'])
- )
- thread_id = cur.lastrowid
- cur.execute(
- "INSERT INTO posts (thread,created,author,content) VALUES (?,current_timestamp,?,?);",
- (thread_id,g.user,content)
- )
- db.commit()
+ abort(400,"title and content can't be empty")
+
+ cur = db.cursor()
+ cur.execute(
+ "INSERT INTO threads (title,creator,created,updated,forum) VALUES (?,?,current_timestamp,current_timestamp,?);",
+ (title,g.user,forum.id)
+ )
+ thread_id = cur.lastrowid
+ cur.execute(
+ "INSERT INTO posts (thread,created,author,content) VALUES (?,current_timestamp,?,?);",
+ (thread_id,g.user,content)
+ )
+ db.commit()
- from . import webhooks
- thread = db.execute("select * from threads where id = ?",(thread_id,)).fetchone()
- webhooks.do_webhooks_thread(forum['id'],thread)
- return redirect(url_for('thread.view_thread',thread_id=thread_id))
- flash(err)
-
-
- return render_template("create_thread.html")
+ from . import webhooks
+ thread = db.execute("select * from threads where id = ?",(thread_id,)).fetchone()
+ webhooks.do_webhooks_thread(forum.id,thread)
+ return redirect(url_for('thread.view_thread',thread_id=thread_id))
+ else:
+ return render_template("create_thread.html")
@forum_route("roles",methods=("GET","POST"))
@requires_bureaucrat
@@ -282,14 +262,14 @@ def edit_roles(forum):
db = get_db()
role_configs = db.execute(
"SELECT * FROM role_config WHERE forum = ? ORDER BY ID ASC",
- (forum['id'],)).fetchall()
+ (forum.id,)).fetchall()
if request.method == "POST":
for config in role_configs:
if 'delete_' + config['role'] in request.form:
db.execute(
"DELETE FROM role_config WHERE forum = ? AND role = ?",
- (forum['id'],config['role']))
+ (forum.id,config['role']))
elif 'roleconfig_' + config['role'] in request.form:
for p in role_permissions:
permission_setting =\
@@ -298,13 +278,13 @@ def edit_roles(forum):
UPDATE role_config SET {p} = ?
WHERE forum = ? AND role = ?;
""",
- (permission_setting,forum['id'], config['role']))
+ (permission_setting,forum.id, config['role']))
db.commit()
flash('roles sucessfully enroled')
- return redirect(url_for('forum.view_forum',forum_id=forum['id']))
+ return redirect(url_for('forum.view_forum',forum_id=forum.id))
role_config_roles = [c['role'] for c in role_configs]
- other_roles = [role for role in get_forum_roles(forum['id']) if not role in role_config_roles]
+ other_roles = [role for role in get_forum_roles(forum.id) if not role in role_config_roles]
return render_template("edit_permissions.html",
forum=forum,
@@ -319,28 +299,28 @@ def add_role(forum):
if not all(c in (" ","-","_") or c.isalnum() for c in name) \
or len(name) > 32:
flash("role name must contain no special characters")
- return redirect(url_for('forum.edit_roles',forum_id=forum['id']))
+ return redirect(url_for('forum.edit_roles',forum_id=forum.id))
if name == "bureaucrat":
flash("cannot configure permissions for bureaucrat")
- return redirect(url_for('forum.edit_roles',forum_id=forum['id']))
+ return redirect(url_for('forum.edit_roles',forum_id=forum.id))
db = get_db()
existing_config = db.execute("""
SELECT * FROM role_config WHERE forum = ? AND role = ?
- """,(forum['id'],name)).fetchone()
+ """,(forum.id,name)).fetchone()
if not existing_config:
db.execute("INSERT INTO role_config (forum,role) VALUES (?,?)",
- (forum['id'],name))
+ (forum.id,name))
db.commit()
- return redirect(url_for('forum.edit_roles',forum_id=forum['id']))
+ return redirect(url_for('forum.edit_roles',forum_id=forum.id))
@forum_route("role",methods=["GET","POST"])
@requires_permission("p_approve")
def view_user_role(forum):
if request.method == "POST":
return redirect(url_for( 'forum.edit_user_role',
- username=request.form['user'],forum_id=forum['id']))
+ username=request.form['user'],forum_id=forum.id))
else:
return render_template("role_assignment.html",forum=forum)
@@ -352,27 +332,27 @@ def edit_user_role(forum, username):
user = db.execute("SELECT * FROM users WHERE username = ?;",(username,)).fetchone()
if user == None:
return redirect(url_for('forum.edit_user_role',
- username=username,forum_id=forum['id']))
+ username=username,forum_id=forum.id))
role = request.form['role']
- if role not in get_forum_roles(forum['id']) and role != "" and role != "bureaucrat":
+ if role not in get_forum_roles(forum.id) and role != "" and role != "bureaucrat":
flash("no such role")
return redirect(url_for('forum.edit_user_role',
- username=username,forum_id=forum['id']))
- if not is_bureaucrat(forum['id'],g.user) and role != "approved" and role != "":
+ username=username,forum_id=forum.id))
+ if not is_bureaucrat(forum.id,g.user) and role != "approved" and role != "":
# only bureaucrats can assign arbitrary roles
abort(403)
existing = db.execute(
"SELECT * FROM role_assignments WHERE user = ? AND forum = ?;",
- (username,forum['id'])).fetchone()
+ (username,forum.id)).fetchone()
if existing:
- db.execute("DELETE FROM role_assignments WHERE user = ? AND forum = ?;",(username,forum['id']))
+ db.execute("DELETE FROM role_assignments WHERE user = ? AND forum = ?;",(username,forum.id))
if role != "":
db.execute(
"INSERT INTO role_assignments (user,role,forum) VALUES (?,?,?);",
- (username,role,forum['id']))
+ (username,role,forum.id))
db.commit()
flash("role assigned assignedly")
- return redirect(url_for('forum.view_forum',forum_id=forum['id']))
+ return redirect(url_for('forum.view_forum',forum_id=forum.id))
else:
user = db.execute("SELECT * FROM users WHERE username = ?;",(username,)).fetchone()
if user == None:
@@ -380,14 +360,14 @@ def edit_user_role(forum, username):
forum=forum,user=username,invalid_user=True)
r = db.execute(
"SELECT role FROM role_assignments WHERE user = ? AND forum = ?;",
- (username,forum['id'])).fetchone()
+ (username,forum.id)).fetchone()
if not r:
assigned_role = ""
else:
assigned_role = r[0]
- role = get_user_role(forum['id'], username)
- if is_bureaucrat(forum['id'], g.user):
- roles = get_forum_roles(forum['id'])
+ role = get_user_role(forum.id, username)
+ if is_bureaucrat(forum.id, g.user):
+ roles = get_forum_roles(forum.id)
roles.remove("other")
roles.add("bureaucrat")
else:
@@ -403,19 +383,19 @@ def forum_config_page(forum, create=False):
desc = request.form["description"]
if len(name) > 100 or len(name.strip()) == 0:
flash("invalid name")
- return redirect(url_for('forum.edit_forum',forum_id=forum['id']))
+ return redirect(url_for('forum.edit_forum',forum_id=forum.id))
elif len(desc) > 6000:
flash("invalid description")
- return redirect(url_for('forum.edit_forum',forum_id=forum['id']))
+ return redirect(url_for('forum.edit_forum',forum_id=forum.id))
if not create:
db.execute("UPDATE forums SET name = ?, description = ? WHERE id = ?",
- (name,desc,forum['id']))
- fid = forum['id']
+ (name,desc,forum.id))
+ fid = forum.id
else:
cur = db.cursor()
cur.execute(
"INSERT INTO forums (name,description,parent) VALUES (?,?,?)",
- (name,desc,forum['id']))
+ (name,desc,forum.id))
new = cur.lastrowid
# creator becomes bureaucrat of new forum
db.execute("INSERT INTO role_assignments (role,user,forum) VALUES (?,?,?)",
@@ -428,9 +408,9 @@ def forum_config_page(forum, create=False):
name = ""
desc = ""
else:
- name = forum['name']
- desc = forum['description']
- cancel_link = url_for('forum.view_forum',forum_id=forum['id'])
+ name = forum.name
+ desc = forum.description
+ cancel_link = url_for('forum.view_forum',forum_id=forum.id)
return render_template("edit_forum.html",create=create,
name=name,description=desc,cancel_link=cancel_link)
@@ -449,7 +429,7 @@ def create_forum(forum):
# if not is_admin: abort(403) # why doesn't this fucking work
# db = get_db()
# unlisted = db.execute(
-# "SELECT * FROM forums WHERE unlisted = 1 AND parent = ?",(forum['id'],))
+# "SELECT * FROM forums WHERE unlisted = 1 AND parent = ?",(forum.id,))
# return render_template('view_unlisted.html',forum=forum,unlisted=unlisted)
@bp.route("/search")