From 1eb77bc3408c75791e2d87acf9cebe240126b23f Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Fri, 7 Oct 2022 23:30:05 +0200 Subject: [PATCH] Show create/modify/update time --- db/sqlite.py | 81 +++++++++++++++++++++++++++++++++++------ main.py | 61 ++++++++++++++++++++++++++++--- templates/comment.html | 6 ++- templates/comments.html | 2 +- templates/index.html | 16 +++++++- templates/subforum.html | 10 ++++- templates/thread.html | 4 +- 7 files changed, 156 insertions(+), 24 deletions(-) diff --git a/db/sqlite.py b/db/sqlite.py index 429197b..bbce05c 100644 --- a/db/sqlite.py +++ b/db/sqlite.py @@ -6,31 +6,56 @@ class DB: pass def get_subforums(self): - return self._db().execute('select forum_id, name, description from subforums') + return self._db().execute(''' + select f.forum_id, name, description, thread_id, title, update_time + from subforums f + left join threads t + on t.thread_id = ( + select tt.thread_id + from threads tt + where f.forum_id = tt.forum_id + order by update_time desc + limit 1 + ) + ''' + ) def get_subforum(self, subforum): - return self._db().execute('select name, description from subforums where forum_id = ?', (subforum,)).fetchone() + return self._db().execute(''' + select name, description + from subforums + where forum_id = ? + ''', + (subforum,) + ).fetchone() def get_threads(self, subforum): - return self._db().execute('select thread_id, title from threads where forum_id = ?', (subforum,)) + return self._db().execute(''' + select t.thread_id, title, t.create_time, t.update_time, t.author_id, name, count(1) + from threads t, users, comments c + where forum_id = ? and user_id = t.author_id and t.thread_id = c.thread_id + group by t.thread_id + ''', + (subforum,) + ) def get_thread(self, thread): db = self._db() - title, text, author, author_id = db.execute(''' - select title, text, name, author_id + title, text, author, author_id, create_time, modify_time = db.execute(''' + select title, text, name, author_id, create_time, modify_time from threads, users where thread_id = ? and author_id = user_id ''', (thread,) ).fetchone() comments = db.execute(''' - select comment_id, parent_id, name, text + select comment_id, parent_id, name, text, create_time, modify_time from comments, users where thread_id = ? and author_id = user_id ''', (thread,) ) - return title, text, author, author_id, comments + return title, text, author, author_id, create_time, modify_time, comments def get_thread_title(self, thread_id): return self._db().execute(''' @@ -41,6 +66,16 @@ class DB: (thread_id,) ).fetchone() + def get_recent_threads(self, limit): + return self._db().execute(''' + select thread_id, title, modify_date + from threads + order by modify_date + limit ? + ''', + (limit,) + ) + def get_comments(self, thread): return self._db().execute(''' select text @@ -67,7 +102,7 @@ class DB: union select comment_id from descendant_of, comments where id = parent_id ) - select id, parent_id, name, text from descendant_of, comments, users + select id, parent_id, name, text, create_time, modify_time from descendant_of, comments, users where id = comment_id and user_id = author_id ''', (comment_id,) @@ -155,8 +190,17 @@ class DB: ''', (thread_id, author_id, text, time, time, thread_id) ) - db.commit() - return c.rowcount > 0 + if c.rowcount > 0: + c.execute(''' + update threads + set update_time = ? + where threads.thread_id = ? + ''', + (time, thread_id) + ) + db.commit() + return True + return False def add_comment_to_comment(self, parent_id, author_id, text, time): db = self._db() @@ -169,8 +213,21 @@ class DB: ''', (parent_id, author_id, text, time, time, parent_id) ) - db.commit() - return c.rowcount > 0 + if c.rowcount > 0: + c.execute(''' + update threads + set update_time = ? + where threads.thread_id = ( + select c.thread_id + from comments c + where comment_id = ? + ) + ''', + (time, parent_id) + ) + db.commit() + return True + return False def _db(self): return sqlite3.connect(self.conn) diff --git a/main.py b/main.py index d9775c2..fc2e806 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,9 @@ -from flask import Flask, render_template, session, request, redirect, url_for, flash +from flask import Flask, render_template, session, request, redirect, url_for, flash, g from db.sqlite import DB import os import passlib.hash import time +from datetime import datetime app = Flask(__name__) db = DB(os.getenv('DB')) @@ -30,13 +31,15 @@ def subforum(forum_id): @app.route('/thread//') def thread(thread_id): user_id = session.get('user_id') - title, text, author, author_id, comments = db.get_thread(thread_id) + title, text, author, author_id, create_time, modify_time, comments = db.get_thread(thread_id) comments = create_comment_tree(comments) return render_template( 'thread.html', title = title, text = text, author = author, + create_time = create_time, + modify_time = modify_time, comments = comments, manage = author_id == user_id, ) @@ -174,24 +177,72 @@ def add_comment_parent(comment_id): class Comment: - def __init__(self, id, author, text): + def __init__(self, id, author, text, create_time, modify_time): self.id = id self.author = author self.text = text self.children = [] + self.create_time = create_time + self.modify_time = modify_time def create_comment_tree(comments): # Collect comments first, then build the tree in case we encounter a child before a parent comment_map = { - comment_id: (Comment(comment_id, author, text), parent_id) - for comment_id, parent_id, author, text + comment_id: (Comment(comment_id, author, text, create_time, modify_time), parent_id) + for comment_id, parent_id, author, text, create_time, modify_time in comments } root = [] + # Build tree for comment, parent_id in comment_map.values(): parent = comment_map.get(parent_id) if parent is not None: parent[0].children.append(comment) else: root.append(comment) + # Sort each comment based on create time + def sort_time(l): + l.sort(key=lambda c: c.modify_time, reverse=True) + for c in l: + sort_time(c.children) + sort_time(root) return root + +@app.context_processor +def utility_processor(): + def format_since(t): + n = time.time_ns() + if n < t: + return 'In a distant future' + + # Try the sane thing first + dt = (n - t) // 10 ** 9 + if dt < 1: + return "less than a second ago" + if dt < 2: + return f"1 second ago" + if dt < 60: + return f"{dt} seconds ago" + if dt < 119: + return f"1 minute ago" + if dt < 3600: + return f"{dt // 60} minutes ago" + if dt < 3600 * 2: + return f"1 hour ago" + if dt < 3600 * 24: + return f"{dt // 3600} hours ago" + if dt < 3600 * 24 * 31: + return f"{dt // (3600 * 24)} days ago" + + # Try some very rough estimate, whatever + f = lambda x: datetime.utcfromtimestamp(x // 10 ** 9) + n, t = f(n), f(t) + def f(x, y, s): + return f'{y - x} {s}{"s" if y - x > 1 else ""} ago' + if t.year < n.year: + return f(t.year, n.year, "year") + if t.month < n.month: + return f(t.month, n.month, "month") + # This shouldn't be reachable, but it's still better to return something + return "incredibly long ago" + return {'format_since': format_since} diff --git a/templates/comment.html b/templates/comment.html index 7387480..ce25b1c 100644 --- a/templates/comment.html +++ b/templates/comment.html @@ -1,6 +1,10 @@ +{% macro author(name, ctime, mtime) %} +

{{ name }} - {{ format_since(ctime) }}{% if ctime != mtime %} (last modified {{ format_since(mtime) }}){% endif %}

+{% endmacro %} + {% macro render_comment_pre(comment) %}
-

{{ comment.author }}

+ {{ author(comment.author, comment.create_time, comment.modify_time) }}

{{ comment.text }}

{% endmacro %} diff --git a/templates/comments.html b/templates/comments.html index 9642482..0e197ee 100644 --- a/templates/comments.html +++ b/templates/comments.html @@ -1,5 +1,5 @@ {% extends 'base.html' %} -{% from 'comment.html' import render_comment, render_comment_pre, render_comment_post, reply %} +{% from 'comment.html' import render_comment, render_comment_pre, render_comment_post, reply with context %} {% block content %} thread diff --git a/templates/index.html b/templates/index.html index 71ad5c8..ae9e694 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,10 +4,22 @@ + - {% for id, name, description in subforums %} + {% for id, name, description, t_id, t_title, t_mtime in subforums %} - + + {% if t_id %} + + {% else %} + + {% endif %} {% endfor %}
ForumLast update
{{ name }} - {{ description }} +

{{ name }}

+

{{ description }}

+
+

{{ t_title }}

+

{{ format_since(t_mtime) }}

+
No threads
diff --git a/templates/subforum.html b/templates/subforum.html index 9729eb2..22c440b 100644 --- a/templates/subforum.html +++ b/templates/subforum.html @@ -6,10 +6,18 @@ + + + + - {% for id, title in threads %} + {% for id, title, ctime, utime, author_id, author, comment_count in threads %} + + + + {% endfor %}
TopicAuthorCreatedUpdatedComments
{{ title }}{{ author }}{{ format_since(ctime) }}{{ format_since(utime) }}{{ comment_count }}
diff --git a/templates/thread.html b/templates/thread.html index d40457f..8094888 100644 --- a/templates/thread.html +++ b/templates/thread.html @@ -1,5 +1,5 @@ {% extends 'base.html' %} -{% from 'comment.html' import render_comment, reply %} +{% from 'comment.html' import render_comment, reply, author as f_author with context %} {% block content %} {% if manage %} @@ -9,7 +9,7 @@
{% endif %} -{{ author }} +{{ f_author(author, create_time, modify_time) }}

{{ text }}

{{ reply() }}