aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--apioforum/db.py12
-rw-r--r--apioforum/forum.py14
-rw-r--r--apioforum/static/style.css30
-rw-r--r--apioforum/templates/base.html2
-rw-r--r--apioforum/templates/common.html4
-rw-r--r--apioforum/templates/config_thread.html21
-rw-r--r--apioforum/templates/view_forum.html26
-rw-r--r--apioforum/templates/view_thread.html21
-rw-r--r--apioforum/thread.py26
9 files changed, 140 insertions, 16 deletions
diff --git a/apioforum/db.py b/apioforum/db.py
index c24aa0e..1d7bd2b 100644
--- a/apioforum/db.py
+++ b/apioforum/db.py
@@ -65,7 +65,19 @@ CREATE TRIGGER posts_au AFTER UPDATE ON posts BEGIN
INSERT INTO posts_fts(posts_fts, rowid, content) VALUES('delete', old.id, old.content);
INSERT INTO posts_fts(rowid, content) VALUES (new.id, new.content);
END;
+""",
"""
+CREATE TABLE tags (
+ id INTEGER PRIMARY KEY,
+ name TEXT NOT NULL,
+ text_colour TEXT NOT NULL,
+ bg_colour TEXT NOT NULL
+);
+CREATE TABLE thread_tags (
+ thread INTEGER NOT NULL REFERENCES threads(id),
+ tag INTEGER NOT NULL REFERENCES tags(id)
+);
+""",
]
def init_db():
diff --git a/apioforum/forum.py b/apioforum/forum.py
index 81674a8..98c71f7 100644
--- a/apioforum/forum.py
+++ b/apioforum/forum.py
@@ -5,11 +5,13 @@ from flask import (
Blueprint, render_template, request,
g, redirect, url_for, flash
)
+
from .db import get_db
from .mdrender import render
bp = Blueprint("forum", __name__, url_prefix="/")
+
@bp.route("/")
def view_forum():
db = get_db()
@@ -21,7 +23,15 @@ def view_forum():
GROUP BY threads.id
ORDER BY threads.updated DESC;
""").fetchall()
- return render_template("view_forum.html",threads=threads)
+ thread_tags = {}
+ #todo: somehow optimise this
+ for thread in threads:
+ thread_tags[thread['id']] = db.execute(
+ """SELECT tags.* FROM tags
+ INNER JOIN thread_tags ON thread_tags.tag = tags.id
+ WHERE thread_tags.thread = ?;
+ """,(thread['id'],)).fetchall()
+ return render_template("view_forum.html",threads=threads,thread_tags=thread_tags)
@bp.route("/create_thread",methods=("GET","POST"))
def create_thread():
@@ -77,4 +87,4 @@ def search():
display_thread_id[ix] = False
last_thread = result["thread"]
rendered_posts = [render(q['content']) for q in results]
- return render_template("search_results.html", results=results, query=query, rendered_posts=rendered_posts, display_thread_id=display_thread_id) \ No newline at end of file
+ return render_template("search_results.html", results=results, query=query, rendered_posts=rendered_posts, display_thread_id=display_thread_id)
diff --git a/apioforum/static/style.css b/apioforum/static/style.css
index df8ce7e..935bde1 100644
--- a/apioforum/static/style.css
+++ b/apioforum/static/style.css
@@ -30,6 +30,20 @@ body { font-family: sans-serif }
.post-anchor-link { color: hsl(0,0%,25%); }
+.thread-top-bar {
+ margin-bottom: 4px;
+}
+
+.thread-top-bar-b {
+ float: right;
+ margin-right: -2px;
+}
+
+.thread-top-bar-b .tag {
+ font-size: .9rem;
+}
+
+
.un-col-1 { color: hsl(0, 100%, 30%) }
.un-col-2 { color: hsl(22.5, 100%, 30%) }
.un-col-3 { color: hsl(45.0, 100%, 30%) }
@@ -69,7 +83,7 @@ nav .links { display: flex; }
.threadlisting { display: contents }
.threadlistings {
display: grid;
- grid-template-columns: 2fr repeat(4,1fr) 0.4fr;
+ grid-template-columns: 2fr repeat(5,1fr) 0.4fr;
}
.threadlisting-part {
@@ -81,6 +95,9 @@ nav .links { display: flex; }
border-bottom: 1px solid black;
}
+ .only-small { display: none !important }
+
+
}
/* small screens */
@@ -101,6 +118,8 @@ nav .links { display: flex; }
border-right: 1px solid black;
border-bottom: 1px solid black;
}
+
+ .only-big { display: none !important }
}
@@ -141,6 +160,9 @@ main {
max-width: 60ch;
margin: auto;
}
+main.widemain {
+ max-width: 120ch;
+}
blockquote {
margin-left: 10px;
@@ -151,3 +173,9 @@ blockquote {
.search-form {
display: inline-block;
}
+
+.tag {
+ font-size: .75rem;
+ padding: 1px 3px;
+ border: 1px solid black;
+}
diff --git a/apioforum/templates/base.html b/apioforum/templates/base.html
index 87b142f..5121b85 100644
--- a/apioforum/templates/base.html
+++ b/apioforum/templates/base.html
@@ -49,9 +49,11 @@
<div class="flashmsg">{{ msg }}</div>
{% endfor %}
+ {% block nmcontent %}
<main>
{%block content %}{% endblock %}
</main>
+ {% endblock %}
<script>/* bees */</script>
</body>
</html>
diff --git a/apioforum/templates/common.html b/apioforum/templates/common.html
index 33aee0b..2e59b2c 100644
--- a/apioforum/templates/common.html
+++ b/apioforum/templates/common.html
@@ -26,3 +26,7 @@
{% macro ts(dt) -%}
<time title="{{dt.isoformat(' ')}}" datetime="{{dt.isoformat(' ')}}">{{dt | fuzzy}}</time>
{%- endmacro %}
+
+{% macro tag(the_tag) -%}
+<span class="tag" style="color: {{the_tag.text_colour}}; background-color: {{the_tag.bg_colour}}">{{the_tag.name}}</span>
+{%- endmacro %}
diff --git a/apioforum/templates/config_thread.html b/apioforum/templates/config_thread.html
index b0dd5f0..973fbf5 100644
--- a/apioforum/templates/config_thread.html
+++ b/apioforum/templates/config_thread.html
@@ -1,13 +1,30 @@
{% extends 'base.html' %}
+{% from 'common.html' import tag %}
{% block header %}<h1>{% block title %}configure thread '{{thread.title}}'{% endblock %}</h1>{% endblock %}
{% block content %}
<form method="post">
+<fieldset>
+<legend>title</legend>
<p>if you want to change the title of this thread, make sure you check the "change title?" box.</p>
<label for="do_title">change title?</label>
-<input type="checkbox" name="do_title"><br>
+<input type="checkbox" id="do_title" name="do_title"><br>
<label for="title">thread title</label>
<input type="text" id="title" name="title" value="{{thread.title}}">
-<br>
+</fieldset>
+<fieldset>
+<legend>tags</legend>
+<p>if you want to change the tags on this thread, make sure you check the "change tags?" box.</p>
+<label for="do_chtags">change tags?</label>
+<input type="checkbox" name="do_chtags" id="do_chtags"><br>
+<ul>
+ {% for the_tag in avail_tags %}
+ <li>
+ <input type="checkbox" id="tag_{{the_tag.id}}" name="tag_{{the_tag.id}}" {%- if the_tag.id in thread_tags %} checked{% endif %}>
+ <label for="tag_{{the_tag.id}}">#{{the_tag.id}} {{tag(the_tag)}}</label>
+ </li>
+ {% endfor %}
+</ul>
+</fieldset>
<p>confirm changes?</p>
<input type="submit" value="confirm">
<a href="{{url_for('thread.view_thread',thread_id=thread.id)}}">cancel</a>
diff --git a/apioforum/templates/view_forum.html b/apioforum/templates/view_forum.html
index dd3d7a8..3edb7f0 100644
--- a/apioforum/templates/view_forum.html
+++ b/apioforum/templates/view_forum.html
@@ -1,7 +1,8 @@
{% extends 'base.html' %}
-{% from 'common.html' import ts %}
+{% from 'common.html' import ts, tag %}
{% block header %}<h1>{% block title %}apioforum{%endblock%}</h1>{%endblock%}
-{%block content%}
+{%block nmcontent%}
+<main class="widemain">
<p>welcome to the apioforum</p>
<p>forum rules: do not be a bad person. do not do bad things.</p>
{% if g.user %}
@@ -12,7 +13,10 @@
<div class="threadlistings">
<div class="threadlisting">
<div class="threadlisting-part threadlisting-part-title threadlisting-header">
- name
+ name<span class="only-small"> &amp; tags</span>
+ </div>
+ <div class="threadlisting-part threadlisting-part-tags threadlisting-header only-big">
+ tags
</div>
<div class="threadlisting-part threadlisting-part-creator threadlisting-header">
creator
@@ -32,7 +36,20 @@
</div>
{%for thread in threads%}
<div class="threadlisting">
- <div class="threadlisting-part threadlisting-part-title"><a href="{{url_for('thread.view_thread',thread_id=thread.id)}}">{{thread.title}}</a></div>
+ <div class="threadlisting-part threadlisting-part-title"><a href="{{url_for('thread.view_thread',thread_id=thread.id)}}">{{thread.title}}</a>
+ {% if thread_tags[thread.id]|length > 0 %}
+ <span class="only-small">
+ {% for the_tag in thread_tags[thread.id] %}
+ {{tag(the_tag)}}
+ {% endfor %}
+ </span>
+ {%endif%}
+ </div>
+ <div class="threadlisting-part threadlisting-part-tags only-big">
+ {% for the_tag in thread_tags[thread.id] %}
+ {{tag(the_tag)}}
+ {% endfor %}
+ </div>
<div class="threadlisting-part threadlisting-part-creator">{{thread.creator}}</div>
<div class="threadlisting-part threadlisting-part-created">{{ts(thread.created)}}</div>
<div class="threadlisting-part threadlisting-part-updated">{{ts(thread.updated)}}</div>
@@ -41,4 +58,5 @@
</div>
{%endfor%}
</div>
+</main>
{%endblock%}
diff --git a/apioforum/templates/view_thread.html b/apioforum/templates/view_thread.html
index eaaf581..abd6aaa 100644
--- a/apioforum/templates/view_thread.html
+++ b/apioforum/templates/view_thread.html
@@ -1,13 +1,24 @@
-{% from 'common.html' import disp_post %}
+{% from 'common.html' import disp_post,tag %}
{% extends 'base.html' %}
{% block header %}
<h1>{%block title %}{{thread.title}}{% endblock %}</h1>
{% endblock %}
{%block content%}
-{% if g.user == thread.creator %}
-<a class="actionbutton" href="{{url_for('thread.config_thread',thread_id=thread_id)}}">configure thread</a>
-{% endif %}
+<div class="thread-top-bar">
+ <span class="thread-top-bar-a">
+ {% if g.user == thread.creator %}
+ <a class="actionbutton" href="{{url_for('thread.config_thread',thread_id=thread.id)}}">configure thread</a>
+ {% endif %}
+ </span>
+ &nbsp;
+ <span class="thread-top-bar-b">
+ {% for the_tag in tags %}
+ {{ tag(the_tag) }}
+ {% endfor %}
+ </span>
+</div>
+
<div class="posts">
{% for post in posts %}
{% call disp_post(post, True) %}
@@ -16,7 +27,7 @@
{% endfor %}
</div>
{% if g.user %}
-<form class="new-post" action="{{url_for('thread.create_post',thread_id=thread_id)}}" method="POST">
+<form class="new-post" action="{{url_for('thread.create_post',thread_id=thread.id)}}" method="POST">
<textarea class="new-post-box" placeholder="your post here..." name="content"></textarea>
<input type="submit" value="yes">
</form>
diff --git a/apioforum/thread.py b/apioforum/thread.py
index 14450af..292fd21 100644
--- a/apioforum/thread.py
+++ b/apioforum/thread.py
@@ -23,8 +23,12 @@ def view_thread(thread_id):
"SELECT * FROM posts WHERE thread = ? ORDER BY created ASC;",
(thread_id,)
).fetchall()
+ tags = db.execute(
+ """SELECT tags.* FROM tags
+ INNER JOIN thread_tags ON thread_tags.tag = tags.id
+ WHERE thread_tags.thread = ?""",(thread_id,)).fetchall()
rendered_posts = [render(q['content']) for q in posts]
- return render_template("view_thread.html",posts=posts,thread=thread,thread_id=thread_id,rendered_posts=rendered_posts)
+ return render_template("view_thread.html",posts=posts,thread=thread,rendered_posts=rendered_posts,tags=tags)
@bp.route("/<int:thread_id>/create_post", methods=("POST",))
def create_post(thread_id):
@@ -109,6 +113,8 @@ def edit_post(post_id):
def config_thread(thread_id):
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()]
+ avail_tags = db.execute("select * from tags order by id").fetchall()
err = None
if g.user is None:
err = "you need to be logged in to do that"
@@ -129,6 +135,22 @@ def config_thread(thread_id):
db.execute("update threads set title = ? where id = ?;",(title,thread_id))
flash("title updated successfully")
db.commit()
+ if 'do_chtags' in request.form:
+ changed = False
+ wanted_tags = []
+ for tagid in range(1,len(avail_tags)+1):
+ current = tagid in thread_tags
+ wanted = f'tag_{tagid}' in request.form
+ print(tagid, current, wanted)
+ if wanted and not current:
+ 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))
+ changed = True
+ if changed:
+ db.commit()
+ flash("tags updated successfully")
if len(err) > 0:
for e in err:
@@ -137,5 +159,5 @@ def config_thread(thread_id):
return redirect(url_for("thread.view_thread",thread_id=thread_id))
- return render_template("config_thread.html", thread=thread)
+ return render_template("config_thread.html", thread=thread,thread_tags=thread_tags,avail_tags=avail_tags)