aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--apioforum/db.py9
-rw-r--r--apioforum/forum.py22
-rw-r--r--apioforum/read.py12
-rw-r--r--apioforum/static/style.css12
-rw-r--r--apioforum/templates/view_forum.html4
-rw-r--r--apioforum/thread.py7
6 files changed, 64 insertions, 2 deletions
diff --git a/apioforum/db.py b/apioforum/db.py
index 24146e2..2d06a13 100644
--- a/apioforum/db.py
+++ b/apioforum/db.py
@@ -233,6 +233,15 @@ CREATE VIEW public_posts AS
JOIN forum_thread_of_post h ON p.id=h.p_id
JOIN public_forums b ON b.id=h.f_id;
""",
+"""
+CREATE TABLE read (
+ user NOT NULL REFERENCES users(username),
+ forum REFERENCES forums(id),
+ thread REFERENCES threads(id),
+ time TIMESTAMP NOT NULL
+);
+ALTER TABLE forums ADD COLUMN updated TIMESTAMP;
+""",
]
diff --git a/apioforum/forum.py b/apioforum/forum.py
index 988c9a5..289cc40 100644
--- a/apioforum/forum.py
+++ b/apioforum/forum.py
@@ -11,6 +11,7 @@ from .db import get_db
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
+from . import read
from sqlite3 import OperationalError
import datetime
import math
@@ -89,6 +90,18 @@ def requires_bureaucrat(f):
return f(forum, *args, **kwargs)
return wrapper
+def set_updated(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()
+ for f in ancestors:
+ db.execute("UPDATE forums SET updated = current_timestamp WHERE id = ?;", (f['id'],))
+ db.commit()
@forum_route("",pagination=True)
@requires_permission("p_view_forum", login_required=False)
@@ -218,6 +231,13 @@ def view_forum(forum,page=1):
WHERE role = 'bureaucrat' AND forum = ?
""",(forum['id'],)).fetchall()
bureaucrats = [b[0] for b in bureaucrats]
+
+
+ if g.user != None:
+ db.execute("DELETE FROM read WHERE user = ? AND forum = ?;", (g.user, forum['id']))
+ db.execute("INSERT INTO read (user,forum,time) VALUES (?,?,current_timestamp);", (g.user, forum['id']))
+ db.commit()
+
return render_template("view_forum.html",
forum=forum,
@@ -231,6 +251,7 @@ def view_forum(forum,page=1):
page=page,
current_sortby=sortby,
tagfilter_tag=tagfilter_tag,
+ is_read=read.is_read,
)
@forum_route("create_thread",methods=("GET","POST"))
@@ -266,6 +287,7 @@ def create_thread(forum):
(thread_id,g.user,content)
)
db.commit()
+ set_updated(forum['id'])
from . import webhooks
thread = db.execute("select * from threads where id = ?",(thread_id,)).fetchone()
diff --git a/apioforum/read.py b/apioforum/read.py
new file mode 100644
index 0000000..289b40e
--- /dev/null
+++ b/apioforum/read.py
@@ -0,0 +1,12 @@
+from flask import g
+from .db import get_db
+
+def is_read(type, id):
+ if g.user == None:
+ return False
+ db = get_db()
+ read = db.execute("SELECT * FROM read WHERE user = ? AND " + type + " = ?;", (g.user, id)).fetchone()
+ if read == None:
+ return False
+ updated = db.execute("SELECT * FROM " + type + "s WHERE id = ?;", (id,)).fetchone()['updated']
+ return updated == None or read['time'] >= updated
diff --git a/apioforum/static/style.css b/apioforum/static/style.css
index 3d6ec22..c77ec69 100644
--- a/apioforum/static/style.css
+++ b/apioforum/static/style.css
@@ -7,6 +7,7 @@ body { font-family: sans-serif; word-wrap: break-word; }
--gray: darkgray;
--light-colour: white;
--username-colour: hsl(0, 0%, 25%);
+ --read-colour: hsl(0, 0%, 30%);
--red: red;
--yellow: yellow;
--blue: blue;
@@ -211,6 +212,16 @@ nav#pages .pageno { align-self: center; }
flex-grow: 1;
}
+.listing-title a {
+ text-decoration: none;
+ color: var(--read-colour);
+}
+
+.unread .listing-title a {
+ text-decoration: underline;
+ color: var(--dark-colour);
+}
+
.thread-listing-tags {
display: flex;
align-items: center;
@@ -359,6 +370,7 @@ textarea {
--gray: lightgray;
--light-colour: black;
--username-colour: hsl(0, 0%, 80%);
+ --read-colour: hsl(0, 0%, 70%);
--yellow: rgb(212, 173, 0);
--blue: rgb(78, 89, 255);
--visited: rgb(173, 110, 209);
diff --git a/apioforum/templates/view_forum.html b/apioforum/templates/view_forum.html
index b6b336f..d37a018 100644
--- a/apioforum/templates/view_forum.html
+++ b/apioforum/templates/view_forum.html
@@ -49,7 +49,7 @@
<div class="forum-list">
{% for subforum in subforums %}
<div class="listing">
- <div class="listing-main">
+ <div class="listing-main {% if not is_read('forum', subforum.id) %}unread{% endif %}">
<div class="listing-title">
<a href="{{url_for('forum.view_forum',forum_id=subforum.id)}}">
{{- subforum.name -}}
@@ -130,7 +130,7 @@ you do not have permission to create threads in this forum
<div class="thread-list">
{%for thread in threads%}
<div class="listing">
- <div class="listing-main">
+ <div class="listing-main {%if not is_read('thread', thread.id)%}unread{% endif %}">
<div class="listing-title">
<a href="{{url_for('thread.view_thread',thread_id=thread.id)}}">
<abbr title="{{ thread.title }}" style="text-decoration:none">{{- thread.title -}}</abbr>
diff --git a/apioforum/thread.py b/apioforum/thread.py
index 83b1adc..656d43d 100644
--- a/apioforum/thread.py
+++ b/apioforum/thread.py
@@ -9,6 +9,7 @@ from flask import (
from .db import get_db
from .roles import has_permission
from . import webhooks
+from . import forum
from .forum import get_avail_tags
bp = Blueprint("thread", __name__, url_prefix="/thread")
@@ -103,6 +104,11 @@ def view_thread(thread_id,page=1):
else:
v = db.execute("SELECT * FROM votes WHERE poll = ? AND user = ? AND current AND NOT is_retraction;",(poll['id'],g.user)).fetchone()
has_voted = v is not None
+
+ if g.user != None:
+ db.execute("DELETE FROM read WHERE user = ? AND thread = ?;", (g.user, thread_id))
+ db.execute("INSERT INTO read (user,thread,time) VALUES (?,?,current_timestamp);", (g.user, thread_id))
+ db.commit()
return render_template(
"view_thread.html",
@@ -256,6 +262,7 @@ def create_post(thread_id):
(thread_id,)
)
db.commit()
+ forum.set_updated(thread['forum'])
post = db.execute("select * from posts where id = ?",(post_id,)).fetchone()
webhooks.do_webhooks_post(thread['forum'],post)
flash("post posted postfully")