From: Chris Fulljames Date: Sun, 26 Jan 2025 21:50:49 +0000 (-0500) Subject: Add initial comment implementation X-Git-Url: https://littlesong.place/gitweb/gitweb.cgi?a=commitdiff_plain;h=9d75cdde286059ad8de0be6dbc5f5ca6a67feed8;p=littlesongplace.git Add initial comment implementation --- diff --git a/main.py b/main.py index d566412..e390285 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,7 @@ from dataclasses import dataclass from datetime import datetime, timezone from logging.handlers import RotatingFileHandler from pathlib import Path, PosixPath +from typing import Optional import bcrypt import bleach @@ -474,6 +475,63 @@ def songs(): tag=tag, song_list=render_template("song-list.html", songs=songs)) +@app.get("/comment") +def comment_get(): + if not "songid" in request.args: + abort(400) # Must have songid + + try: + song = Song.by_id(request.args["songid"]) + except ValueError: + abort(404) # Invald songid + + if not "userid" in session: + abort(401) # Must be logged in + + comment = None + if "commentid" in request.args: + commentid = request.args["commentid"] + comment = query_db("select * from song_comments inner join users on song_comments.userid == users.userid where commentid = ?", [commentid], one=True) + + session["previous_page"] = request.referrer + return render_template("comment.html", song=song, comment=comment) + +@app.post("/comment") +def comment_post(): + if not "songid" in request.args: + abort(400) # Must have songid + + try: + song = Song.by_id(request.args["songid"]) + except ValueError: + abort(404) # Invald songid + + comment = None + if "commentid" in request.args: + commentid = request.args["commentid"] + comment = query_db("select * from song_comments inner join users on song_comments.userid == users.userid where commentid = ?", [commentid], one=True) + if not comment: + abort(404) # Invalid comment + + if not "userid" in session: + abort(401) # Must be logged in + + # Add new comment + timestamp = datetime.now(timezone.utc).isoformat() + content = request.form["content"] + userid = session["userid"] + songid = request.args["songid"] + replytoid = request.args.get("commentid", None) + query_db( + "insert into song_comments (songid, userid, replytoid, created, content) values (?, ?, ?, ?, ?)", + args=[songid, userid, replytoid, timestamp, content]) + get_db().commit() + + if "previous_page" in session: + return redirect(session["previous_page"]) + else: + return redirect("/") + @app.get("/site-news") def site_news(): return render_template("news.html") @@ -545,6 +603,16 @@ class Song: def json(self): return json.dumps(vars(self)) + def get_comments(self): + comments = query_db("select * from song_comments inner join users on song_comments.userid == users.userid where songid = ?", [self.songid]) + # Top-level comments + song_comments = sorted([dict(c) for c in comments if c["replytoid"] is None], key=lambda c: c["created"]) + # Replies (can only reply to top-level) + for comment in song_comments: + comment["replies"] = sorted([c for c in comments if c["replytoid"] == comment["commentid"]], key=lambda c: c["created"]) + + return song_comments + @classmethod def by_id(cls, songid): songs = cls._from_db("select * from songs inner join users on songs.userid = users.userid where songid = ?", [songid]) @@ -576,7 +644,7 @@ class Song: @classmethod def _from_db(cls, query, args=()): songs_data = query_db(query, args) - tags, collabs = cls._get_tags_and_collabs_for_songs(songs_data) + tags, collabs = cls._get_info_for_songs(songs_data) songs = [] for sd in songs_data: song_tags = [t["tag"] for t in tags[sd["songid"]]] @@ -586,7 +654,7 @@ class Song: return songs @classmethod - def _get_tags_and_collabs_for_songs(cls, songs): + def _get_info_for_songs(cls, songs): tags = {} collabs = {} for song in songs: diff --git a/schema.sql b/schema.sql index 87470fa..be54410 100644 --- a/schema.sql +++ b/schema.sql @@ -35,3 +35,16 @@ CREATE TABLE song_tags ( ); CREATE INDEX idx_song_tags_tag ON song_tags(tag); +DROP TABLE IF EXISTS song_comments; +CREATE TABLE song_comments ( + commentid INTEGER PRIMARY KEY, + songid INTEGER NOT NULL, + userid INTEGER NOT NULL, + replytoid INTEGER, + created TEXT NOT NULL, + content TEXT NOT NULL, + FOREIGN KEY(songid) REFERENCES songs(songid), + FOREIGN KEY(userid) REFERENCES users(userid) +); +CREATE INDEX idx_comments_by_song ON song_comments(songid); + diff --git a/templates/comment.html b/templates/comment.html new file mode 100644 index 0000000..2ed0100 --- /dev/null +++ b/templates/comment.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block title %}Write a Comment{% endblock %} + +{% block body %} + +

Write a Comment

+ +

+Commenting on {{ song.title }} +

+ +{% if comment %} +

+In reply to: +{{ comment['username'] }} +
+{{ comment['content'] }} +

+{% endif %} + +
+ + +
+ +{% endblock %} diff --git a/templates/song-list.html b/templates/song-list.html index 730efcf..4809f9f 100644 --- a/templates/song-list.html +++ b/templates/song-list.html @@ -10,7 +10,7 @@
-
- +
{{ song.username }} @@ -62,6 +62,29 @@ {{ tag }} {% endfor %}
+ + +
+ Comments: + Add a Comment + + {% for comment in song.get_comments() %} +
+ {{ comment['username'] }} +

{{ comment['content'] }}

+ + {% for reply in comment['replies'] %} +
+ {{ reply['username'] }} +

{{ reply['content'] }}

+
+ {% endfor %} + + Reply +
+ {% endfor %} +
+ {% endfor %} diff --git a/todo.txt b/todo.txt index 473c749..48f88e5 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,16 @@ -- Dark mode? +- Comments: + - Leave comment + - Delete comment + - Notifications +- YouTube importer - Autoplay toggle -- Comments, notifications -- Tips and Tricks -- Multiline descriptions +- Volume control - Shuffle all -- Homepage activity log +- Song sorter for song lists +- Additional song info in player (collabs, description, tags) +- Tips and Tricks (or html helper for bio/descriptions?) +- Multiline/html descriptions +- Dark mode/site color customization - Admin accounts - Account deletion - Change password (require email?) @@ -24,9 +30,5 @@ - Delete - Pin to profile - Albums? -- Comments: - - Leave comment - - Delete comment - - Notifications - Song/User Search