]> littlesong.place Git - littlesongplace.git/commitdiff
More work on song editing (incomplete)
authorChris Fulljames <christianfulljames@gmail.com>
Wed, 8 Jan 2025 12:35:59 +0000 (07:35 -0500)
committerChris Fulljames <christianfulljames@gmail.com>
Wed, 8 Jan 2025 12:35:59 +0000 (07:35 -0500)
main.py
templates/edit-song.html [new file with mode: 0644]
templates/profile.html
todo.txt

diff --git a/main.py b/main.py
index 75e992536253b35afcf9d9813eb02b3d2378e49e..d915714193f7f53d4f9ea7b0be9abc205629b0ab 100644 (file)
--- a/main.py
+++ b/main.py
@@ -1,3 +1,4 @@
+from dataclasses import dataclass
 import os
 import shutil
 import sqlite3
@@ -123,14 +124,42 @@ def users_profile(profile_username):
             songs_tags=tags,
             songs_collaborators=collabs)
 
-@app.post("/uploadsong")
-def upload_song():
-    if not "username" in session:
-        abort(401)
+@app.get("/edit-song/<int:songid>")
+def edit_song(songid=None):
+    if not "userid" in session:
+        return redirect("/login")  # Must be logged in to edit
+
+    if songid:
+        try:
+            song = Song.from_db(songid)
+        except ValueError:
+            abort(404)
+
+        return render_template("edit-song.html", song=song)
+
+
+@app.post("/upload-song/<int:songid>")
+def upload_song(songid=None):
+    if not "userid" in session:
+        return redirect("/login")  # Must be logged in to edit
+
+    error = validate_song_form()
 
-    username = session["username"]
-    userid = session["userid"]
+    if not error:
+        userid = session["userid"]
+        if songid:
+            error = update_song(file, userid, title, description, tags, collaborators, songid)
+        else:
+            error = create_song(file, userid, title, description, tags, collaborators)
+
+    if not error:
+        username = session["username"]
+        return redirect("/users/{username}")
+
+    else:
+        return redirect(request.referrer)
 
+def validate_song_form():
     file = request.files["song"]
     title = request.form["title"]
     description = request.form["description"]
@@ -163,15 +192,7 @@ def upload_song():
             flash(f"'{collab}' is not a valid collaborator name", "error")
             error = True
 
-    if not error:
-        if "songid" in request.args:
-            # Update existing song
-            update_song(file, userid, title, description, tags, collaborators)
-        else:
-            # Uploading new song
-            create_song(file, userid, title, description, tags, collaborators)
-
-    return redirect(request.referrer)
+    return error
 
 def get_user_path(userid):
     userpath = DATA_DIR / "songs" / str(userid)
@@ -186,6 +207,13 @@ def update_song(file, userid, title, description, tags, collaborators):
     except ValueError:
         abort(400)
 
+    # Make sure song exists and the logged-in user owns it
+    song_data = query_db("select userid from songs where songid = ?", [songid], one=True)
+    if song_data is None:
+        abort(400)
+    elif userid != song_data["userid"]:
+        abort(401)
+
     if file:
         with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
             file.save(tmp_file)
@@ -365,3 +393,25 @@ def gen_key():
     import secrets
     print(secrets.token_hex())
 
+@dataclass
+class Song:
+    id: int
+    title: str
+    description: str
+    tags: list[str]
+    collaborators: list[str]
+
+    @classmethod
+    def from_db(cls, songid):
+        song_data = query_db("select * from songs where songid = ?", [songid], one=True)
+        if song_data is None:
+            raise ValueError(f"No song for ID {songid:d}")
+
+        tags_data = query_db("select * from song_tags where songid = ?", [songid])
+        collaborators_data = query_db("select * from song_collaborators where songid = ?", [song])
+
+        tags = [t["tag"] for t in tags_data]
+        collabs = [c["name"] for c in collaborators_data]
+
+        return cls(song_data["songid"], song_data["title"], song_data["description"], tags, collabs)
+
diff --git a/templates/edit-song.html b/templates/edit-song.html
new file mode 100644 (file)
index 0000000..5a1879f
--- /dev/null
@@ -0,0 +1,46 @@
+{% extends "base.html" %}
+
+{% block title %}{% if song %}Edit Song{% else %}Upload Song{% endif %}{% endblock %}
+
+{% block body %}
+
+<form action="/uploadsong" method="post" enctype="multipart/form-data">
+    <h2>Upload a new song</h2>
+    <div class="upload-form">
+        <label for="song">{% if editing %}Replace {% endif %}mp3 File</label>
+        <input type="file" name="song" accept=".mp3" id="file-select" required></input>
+    </div>
+    <div class="upload-form">
+        <label for="title">Title</label>
+        <input type="text" name="title" id="song-title" value="{{ title }}" required></input>
+    </div>
+    <div class="upload-form">
+        <label for="description">Description</label>
+        <textarea name="description" value="{{ description }}"></textarea>
+    </div>
+    <div class="upload-form">
+        <label for="tags">Tags</label>
+        <input type="text" name="tags" placeholder="country, extratone, vocals, ..." value="{{ tags }}"></input>
+    </div>
+    <div class="upload-form">
+        <label for="collabs">Collaborators</label>
+        <input type="text" name="collabs" placeholder="@fren_user, John Doe, ..." value="{{ collaborators }}"></input>
+    </div>
+    <div class="upload-form">
+        <input type="submit" value="Upload"></input>
+    </div>
+</form>
+
+<!-- Automatically set song name from file name -->
+<script>
+document.getElementById("file-select").addEventListener("change", function(e) {
+    var songTitle = document.getElementById("song-title");
+    if (e.target.files[0] && !songTitle.value) {
+        var name = e.target.files[0].name;
+        songTitle.value = name.substring(0, name.length - 4);
+    }
+});
+</script>
+{% endif %}
+
+{% endblock %}
index dfa66ae7f1e196a7b9c81ecafdc1eb4a0f83c340..a3fc591d537ede9ba16d05a39dde52f15d2be021 100644 (file)
@@ -6,47 +6,13 @@
 
 <h1 class="profile-name">{{ name }}</h1>
 
-{% if name == username %}
-<form action="/uploadsong" method="post" enctype="multipart/form-data">
-    <h2>Upload a new song</h2>
-    <div class="upload-form">
-        <label for="song">mp3 File</label>
-        <input type="file" name="song" accept=".mp3" id="file-select" required></input>
-    </div>
-    <div class="upload-form">
-        <label for="title">Title</label>
-        <input type="text" name="title" id="song-title" required></input>
-    </div>
-    <div class="upload-form">
-        <label for="title">Description</label>
-        <textarea name="description"></textarea>
-    </div>
-    <div class="upload-form">
-        <label for="tags">Tags</label>
-        <input type="text" name="tags" placeholder="country, extratone, vocals, ..."></input>
-    </div>
-    <div class="upload-form">
-        <label for="collabs">Collaborators</label>
-        <input type="text" name="collabs" placeholder="@fren_user, John Doe, ..."></input>
-    </div>
-    <div class="upload-form">
-        <input type="submit" value="Upload"></input>
-    </div>
-</form>
-{% endif %}
+<h2>Songs</h2>
 
-<!-- Automatically set song name from file name -->
-<script>
-document.getElementById("file-select").addEventListener("change", function(e) {
-    var songTitle = document.getElementById("song-title");
-    if (e.target.files[0] && !songTitle.value) {
-        var name = e.target.files[0].name;
-        songTitle.value = name.substring(0, name.length - 4);
-    }
-});
-</script>
+<!-- Upload New Song button -->
+{% if session["userid"] == userid %}
+<a href="/edit-song">Upload New Song</a>
+{% endif %}
 
-<h2>Songs</h2>
 
 <!-- TODO: This is duplicated in songs-by-tag.html -->
 {% for song in songs %}
@@ -55,8 +21,10 @@ document.getElementById("file-select").addEventListener("change", function(e) {
     <div class="song-title"><h3>{{ song["title"] }}</h3></div>
 
     <!-- Owner-Specific Buttons (Edit/Delete) -->
-    {% if name == username %}
-    <!-- TODO: Edit button -->
+    {% if session["userid"] == userid %}
+    <div class="song-edit-button">
+    <a href="/edit-song/{{ song["userid"] }}/{{ song["songid"] }}">Edit</a>
+    </div>
     <div class="song-delete-button">
     <a href="/delete-song/{{ song["userid"] }}/{{ song["songid"] }}">Delete</a>
     </div>
@@ -89,3 +57,4 @@ document.getElementById("file-select").addEventListener("change", function(e) {
 {% endfor %}
 
 {% endblock %}
+
index b3c60e8f4aa971b8688a6ae86eeca3bb55317187..e918c77387ce6b3974f9bedcf8a7b0a922a67085 100644 (file)
--- a/todo.txt
+++ b/todo.txt
@@ -1,3 +1,4 @@
+- edit-song.html: use song object
 - delete song
 - edit song info
 - user bio