aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2022-08-11 01:51:00 +0100
committerubq323 <ubq323@ubq323.website>2022-08-11 01:51:00 +0100
commitc161f9e778197e3d9c02ea05f4f199c2d01b6662 (patch)
tree8168d2ab91d1cc16910b34aa6fdfa8aebf86da1a
parent6e3e9b510368a91d523b15732295d241cdd8cecc (diff)
create dedicated post module, move things around a lot, remove breadcrumbs since they aren't needed any more
-rw-r--r--apioforum/orm.py6
-rw-r--r--apioforum/post.py33
-rw-r--r--apioforum/templates/common.html27
-rw-r--r--apioforum/thread.py99
4 files changed, 97 insertions, 68 deletions
diff --git a/apioforum/orm.py b/apioforum/orm.py
index c87dbdd..97124c7 100644
--- a/apioforum/orm.py
+++ b/apioforum/orm.py
@@ -8,8 +8,9 @@ class DBObj:
# DO NOT pass anything with sql special characters in as the table name
super().__init_subclass__(**kwargs)
cls.table_name = table
+
@classmethod
- def fetch(cls,*,id):
+ def fetch(cls, *, id):
"""fetch an object from the database, looked up by id."""
db = get_db()
# xxx this could be sped up by caching this query maybe instead of
@@ -19,8 +20,9 @@ class DBObj:
return None
item = cls.from_row(row)
return item
+
@classmethod
- def from_row(cls,row):
+ def from_row(cls, row):
# doesn't handle the ability to set fields yet
# we will use something like properties instead
# so this is somewhat bleh for now
diff --git a/apioforum/post.py b/apioforum/post.py
new file mode 100644
index 0000000..86753ad
--- /dev/null
+++ b/apioforum/post.py
@@ -0,0 +1,33 @@
+# wow, a dedicated module
+#
+
+from .orm import DBObj
+from .thread import POSTS_PER_PAGE
+from flask import url_for
+
+class Post(DBObj,table="posts"):
+ fields = ["id","content","thread","author","created","edited","updated","vote","deleted"]
+
+ def which_page(self):
+ """ return what page of a thread the given post is on
+
+ assumes post ids within a thread are monotonically increasing, which
+ is probably correct
+ """
+ db = get_db()
+ amt_before = db.execute("""
+ select count(*) as c from posts
+ where thread = ? and id < ?""",
+ (self.thread,self.id)).fetchone()['c']
+
+ page = 1+math.floor(amt_before/POSTS_PER_PAGE)
+ return page
+
+ def jump_url(self,*,external=False):
+ page = self.which_page()
+ return url_for(
+ "thread.view_thread",
+ thread_id = self.thread,
+ page=page,
+ _external=external)+"#post"+str(self.id)
+
diff --git a/apioforum/templates/common.html b/apioforum/templates/common.html
index fae4b7c..5677073 100644
--- a/apioforum/templates/common.html
+++ b/apioforum/templates/common.html
@@ -87,33 +87,6 @@
<a class="actionbutton" href="{{href}}">{{name}}</a>
{%- endmacro %}
-{% macro breadcrumb() %}
-<nav aria-label="Breadcrumb">
-<ol class="breadcrumbs">
- {{- caller() -}}
-</ol>
-</nav>
-{% endmacro %}
-
-{% macro forum_bc_entries(forum_id) -%}
- {%- for f in forum_path(forum_id) -%}
- <li><a href="{{url_for('forum.view_forum',forum_id=f.id)}}">{{ f.name }}</a></li>
- {%- endfor %}
-{%- endmacro %}
-
-{% macro forum_breadcrumb(forum) %}
- {%- call breadcrumb() %}
- {{ forum_bc_entries(forum.id) }}
- {% endcall -%}
-{% endmacro %}
-
-{% macro thread_breadcrumb(thread) %}
- {%- call breadcrumb() %}
- {{ forum_bc_entries(thread.forum) }}
- <li>{{ thread.title }}</li>
- {% endcall -%}
-{% endmacro %}
-
{% macro vote_meter(poll) %}
{% set total_votes = poll.total_votes %}
{% set n = namespace() %}
diff --git a/apioforum/thread.py b/apioforum/thread.py
index a2ba6f5..f80786c 100644
--- a/apioforum/thread.py
+++ b/apioforum/thread.py
@@ -11,9 +11,34 @@ from .db import get_db
from .roles import has_permission
from . import webhooks
from .forum import Forum
+from .orm import DBObj
-class Thread:
+POSTS_PER_PAGE = 28
+
+class Thread(DBObj,table="threads"):
fields = ["id","title","creator","created","updated","forum","poll"]
+
+ # maybe this should be on Post instead?????
+ @staticmethod
+ def which_page(post):
+ """ return what page of a thread the given post is on
+
+ assumes post ids within a thread are monotonically increasing, which
+ is probably correct
+ """
+ db = get_db()
+ amt_before = db.execute("""
+ select count(*) as c from posts
+ where thread = ? and id < ?""",
+ (post.thread,post.id)).fetchone()['c']
+
+ page = 1+math.floor(amt_before/POSTS_PER_PAGE)
+ return page
+
+
+
+
+
@@ -29,17 +54,16 @@ def thread_route(relative_path, pagination=False, **kwargs):
@bp.route(path, **kwargs)
@functools.wraps(f)
def wrapper(thread_id, *args, **kwargs):
- thread = Thread.fetch(id=forum_id)
+ thread = Thread.fetch(id=thread_id)
if thread == None:
abort(404)
- return f(forum, *args, **kwargs)
+ return f(thread, *args, **kwargs)
if pagination:
wrapper = bp.route(path+"/page/<int:page>", **kwargs)(wrapper)
return decorator
-POSTS_PER_PAGE = 28
def which_page(post_id,return_thread_id=False):
# on which page lieth the post in question?
@@ -69,8 +93,6 @@ def post_jump(post_id,*,external=False):
page,thread_id=which_page(post_id,True)
return url_for("thread.view_thread",thread_id=thread_id,page=page,_external=external)+"#post_"+str(post_id)
-#@bp.route("/<int:thread_id>")
-#@bp.route("/<int:thread_id>/page/<int:page>")
@thread_route("",pagination=True)
def view_thread(thread,page=1):
if page < 1:
@@ -91,14 +113,14 @@ def view_thread(thread,page=1):
(page-1)*POSTS_PER_PAGE,
)).fetchall()
- num_posts = db.execute("SELECT count(*) as count FROM posts WHERE posts.thread = ?",(thread_id,)).fetchone()['count']
+ num_posts = db.execute("SELECT count(*) as count FROM posts WHERE posts.thread = ?",(thread.id,)).fetchone()['count']
max_pageno = math.ceil(num_posts/POSTS_PER_PAGE)
tags = db.execute(
"""SELECT tags.* FROM tags
INNER JOIN thread_tags ON thread_tags.tag = tags.id
WHERE thread_tags.thread = ?
- ORDER BY tags.id""",(thread_id,)).fetchall()
+ ORDER BY tags.id""",(thread.id,)).fetchall()
poll = None
votes = None
if thread.poll is not None:
@@ -158,12 +180,12 @@ def register_vote(thread,pollval):
UPDATE votes
SET current = 0
WHERE poll = ? AND user = ?;
- """,(thread['poll'],g.user))
+ """,(thread.poll,g.user))
cur.execute("""
INSERT INTO votes (user,poll,option_idx,time,current,is_retraction)
VALUES (?,?,?,current_timestamp,1,?);
- """,(g.user,thread['poll'],option_idx,is_retraction))
+ """,(g.user,thread.poll,option_idx,is_retraction))
vote_id = cur.lastrowid
return vote_id
@@ -182,16 +204,16 @@ def create_poll(thread_id):
err = "that thread does not exist"
elif g.user is None:
err = "you need to be logged in to do that"
- elif g.user != thread['creator'] and \
- not has_permission(thread['forum'],g.user,"p_manage_threads"):
+ elif g.user != thread.creator and \
+ not has_permission(thread.forum,g.user,"p_manage_threads"):
err = "you can only create polls on threads that you own"
- elif thread['poll'] is not None:
+ elif thread.poll is not None:
err = "a poll already exists for that thread"
elif not len(polltitle) > 0:
err = "poll title can't be empty"
elif len(polloptions) < 2:
err = "you must provide at least 2 options"
- elif not has_permission(thread['forum'], g.user, "p_create_polls"):
+ elif not has_permission(thread.forum, g.user, "p_create_polls"):
err = "you do not have permission to do that"
if err is not None:
@@ -222,17 +244,17 @@ def delete_poll(thread_id):
err = "that thread does not exist"
elif g.user is None:
err = "you need to be logged in to do that"
- elif g.user != thread['creator'] and not \
- has_permission(thread['forum'], g.user, "p_manage_threads"):
+ elif g.user != thread.creator and not \
+ has_permission(thread.forum, g.user, "p_manage_threads"):
err = "you can only delete polls on threads that you own"
- elif thread['poll'] is None:
+ elif thread.poll is None:
err = "there is no poll to delete on this thread"
if err is not None:
flash(err)
return fail
else:
- pollid = thread['poll']
+ pollid = thread.poll
db.execute("UPDATE posts SET vote = NULL WHERE thread = ?",(thread_id,)) # this assumes only max one poll per thread
db.execute("DELETE FROM votes WHERE poll = ?",(pollid,))
db.execute("DELETE FROM poll_options WHERE poll = ?",(pollid,))
@@ -253,16 +275,16 @@ def create_post(thread_id):
flash("you cannot post an empty message")
elif not thread:
flash("that thread does not exist")
- elif not has_permission(thread['forum'], g.user, "p_reply_threads"):
+ elif not has_permission(thread.forum, g.user, "p_reply_threads"):
flash("you do not have permission to do this")
- elif not has_permission(thread['forum'], g.user, "p_view_threads"):
+ elif not has_permission(thread.forum, g.user, "p_view_threads"):
flash("you do not have permission to do this")
- elif not has_permission(thread['forum'], g.user, "p_vote") \
+ elif not has_permission(thread.forum, g.user, "p_vote") \
and 'poll' in request.form:
flash("you do not have permission to do this")
else:
vote_id = None
- if thread['poll'] is not None:
+ if thread.poll is not None:
pollval = request.form.get('poll')
try:
vote_id = register_vote(thread,pollval)
@@ -282,7 +304,7 @@ def create_post(thread_id):
)
db.commit()
post = db.execute("select * from posts where id = ?",(post_id,)).fetchone()
- webhooks.do_webhooks_post(thread['forum'],post)
+ webhooks.do_webhooks_post(thread.forum,post)
flash("post posted postfully")
return redirect(post_jump(post_id))
return redirect(url_for('thread.view_thread',thread_id=thread_id))
@@ -295,7 +317,7 @@ def delete_post(post_id):
if post is None:
flash("that post doesn't exist")
return redirect("/")
- if post['author'] != g.user and not has_permission(thread['forum'], g.user, "p_delete_posts"):
+ if post['author'] != g.user and not has_permission(thread.forum, g.user, "p_delete_posts"):
flash("you do not have permission to do that")
return redirect(url_for("thread.view_thread",thread_id=post["thread"]))
if request.method == "POST":
@@ -317,7 +339,7 @@ def delete_thread(thread_id):
if thread is None:
flash("that thread doesn't exist")
return redirect("/")
- if not has_permission(thread['forum'], g.user, "p_delete_posts"):
+ if not has_permission(thread.forum, g.user, "p_delete_posts"):
flash("you do not have permission to do that")
return redirect(url_for("thread.view_thread",thread_id=thread_id))
if request.method == "POST":
@@ -325,7 +347,7 @@ def delete_thread(thread_id):
db.execute("DELETE FROM threads WHERE id = ?",(thread_id,))
db.commit()
flash("thread deleted deletedly")
- return redirect(url_for("forum.view_forum",forum_id=thread['forum']))
+ return redirect(url_for("forum.view_forum",forum_id=thread.forum))
else:
count = db.execute("SELECT num_replies FROM number_of_posts WHERE thread = ?",
(thread_id,)).fetchone()[0]
@@ -380,33 +402,32 @@ def view_post(post_id):
-@bp.route("/<int:thread_id>/config",methods=["GET","POST"])
-def config_thread(thread_id):
+@thread_route("config",methods=["GET","POST"])
+def config_thread(thread):
db = get_db()
- thread = db.execute("select * from threads where id = ?",(thread_id,)).fetchone()
- thread_tags = [r['tag'] for r in db.execute("select tag from thread_tags where thread = ?",(thread_id,)).fetchall()]
- forum = Forum.fetch(id=thread['forum'])
+ thread_tags = [r['tag'] for r in db.execute("select tag from thread_tags where thread = ?",(thread.id,)).fetchall()]
+ forum = Forum.fetch(id=thread.forum)
avail_tags = forum.avail_tags()
err = None
if g.user is None:
err = "you need to be logged in to do that"
- elif not has_permission(thread['forum'], g.user, "p_view_threads"):
+ elif not has_permission(thread.forum, g.user, "p_view_threads"):
err = "you do not have permission to do that"
- elif g.user != thread['creator'] and not has_permission(thread['forum'], g.user, "p_manage_threads"):
+ elif g.user != thread.creator and not has_permission(thread.forum, g.user, "p_manage_threads"):
err = "you can only configure threads that you own"
if err is not None:
flash(err)
- return redirect(url_for("thread.view_thread",thread_id=thread_id))
+ return redirect(url_for("thread.view_thread",thread_id=thread.id))
if request.method == "POST":
err = []
- if request.form['title'] != thread['title']:
+ if request.form['title'] != thread.title:
title = request.form['title']
if len(title.strip()) == 0:
err.append("title can't be empty")
else:
- db.execute("update threads set title = ? where id = ?;",(title,thread_id))
+ db.execute("update threads set title = ? where id = ?;",(title,thread.id))
flash("title updated successfully")
db.commit()
changed = False
@@ -415,10 +436,10 @@ def config_thread(thread_id):
current = tagid in thread_tags
wanted = f'tag_{tagid}' in request.form
if wanted and not current:
- db.execute("insert into thread_tags (thread, tag) values (?,?)",(thread_id,tagid))
+ db.execute("insert into thread_tags (thread, tag) values (?,?)",(thread.id,tagid))
changed = True
elif current and not wanted:
- db.execute("delete from thread_tags where thread = ? and tag = ?",(thread_id,tagid))
+ db.execute("delete from thread_tags where thread = ? and tag = ?",(thread.id,tagid))
changed = True
if changed:
db.commit()
@@ -428,7 +449,7 @@ def config_thread(thread_id):
for e in err:
flash(e)
else:
- return redirect(url_for("thread.view_thread",thread_id=thread_id))
+ return redirect(url_for("thread.view_thread",thread_id=thread.id))
return render_template("config_thread.html", thread=thread,thread_tags=thread_tags,avail_tags=avail_tags)