lots of post-DB cleanup

This commit is contained in:
ari melody 2024-09-02 00:15:23 +01:00
parent 965d6f5c3e
commit c9d950d2b2
Signed by: ari
GPG key ID: CF99829C92678188
23 changed files with 412 additions and 550 deletions

View file

@ -1,7 +1,7 @@
{{define "release"}}
<div class="release">
<div class="release-artwork">
<img src="{{.Artwork}}" alt="" width="128" loading="lazy">
<img src="{{.GetArtwork}}" alt="" width="128" loading="lazy">
</div>
<div class="release-info">
<h3 class="release-title">

View file

@ -57,7 +57,7 @@ func Handler() http.Handler {
}
releases := []musicModel.FullRelease{}
for _, release := range dbReleases {
fullRelease, err := musicDB.GetFullRelease(global.DB, release)
fullRelease, err := musicDB.GetFullRelease(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to pull full release data for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -6,24 +6,25 @@ import (
"strings"
"arimelody.me/arimelody.me/global"
db "arimelody.me/arimelody.me/music/controller"
"arimelody.me/arimelody.me/music/model"
controller "arimelody.me/arimelody.me/music/controller"
)
func serveRelease() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
slices := strings.Split(r.URL.Path[1:], "/")
releaseID := slices[0]
release, err := controller.GetRelease(global.DB, releaseID)
release, err := db.GetFullRelease(global.DB, releaseID)
if err != nil {
fmt.Printf("FATAL: Failed to pull release %s: %s\n", releaseID, err)
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
return
}
fmt.Printf("FATAL: Failed to pull full release data for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
if release == nil {
http.NotFound(w, r)
return
}
authorised := GetSession(r) != nil
if !authorised && !release.Visible {
@ -31,32 +32,25 @@ func serveRelease() http.Handler {
return
}
fullRelease, err := controller.GetFullRelease(global.DB, release)
if err != nil {
fmt.Printf("FATAL: Failed to pull full release data for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
if len(slices) > 1 {
switch slices[1] {
case "editcredits":
serveEditCredits(fullRelease).ServeHTTP(w, r)
serveEditCredits(release).ServeHTTP(w, r)
return
case "addcredit":
serveAddCredit(fullRelease).ServeHTTP(w, r)
serveAddCredit(release).ServeHTTP(w, r)
return
case "newcredit":
serveNewCredit().ServeHTTP(w, r)
return
case "editlinks":
serveEditLinks(fullRelease).ServeHTTP(w, r)
serveEditLinks(release).ServeHTTP(w, r)
return
case "edittracks":
serveEditTracks(fullRelease).ServeHTTP(w, r)
serveEditTracks(release).ServeHTTP(w, r)
return
case "addtrack":
serveAddTrack(fullRelease).ServeHTTP(w, r)
serveAddTrack(release).ServeHTTP(w, r)
return
case "newtrack":
serveNewTrack().ServeHTTP(w, r)
@ -66,7 +60,7 @@ func serveRelease() http.Handler {
return
}
err = pages["release"].Execute(w, fullRelease)
err = pages["release"].Execute(w, release)
if err != nil {
fmt.Printf("Error rendering admin release page for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -87,7 +81,7 @@ func serveEditCredits(release *model.FullRelease) http.Handler {
func serveAddCredit(release *model.FullRelease) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
artists, err := controller.GetArtistsNotOnRelease(global.DB, release.Release)
artists, err := db.GetArtistsNotOnRelease(global.DB, release.Release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to pull artists not on %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -114,7 +108,7 @@ func serveAddCredit(release *model.FullRelease) http.Handler {
func serveNewCredit() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
artistID := strings.Split(r.URL.Path, "/")[3]
artist, err := controller.GetArtist(global.DB, artistID)
artist, err := db.GetArtist(global.DB, artistID)
if err != nil {
fmt.Printf("FATAL: Failed to pull artists %s: %s\n", artistID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -158,7 +152,7 @@ func serveEditTracks(release *model.FullRelease) http.Handler {
func serveAddTrack(release *model.FullRelease) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tracks, err := controller.GetTracksNotOnRelease(global.DB, release.Release)
tracks, err := db.GetTracksNotOnRelease(global.DB, release.Release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to pull tracks not on %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -186,7 +180,7 @@ func serveAddTrack(release *model.FullRelease) http.Handler {
func serveNewTrack() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
trackID := strings.Split(r.URL.Path, "/")[3]
track, err := controller.GetTrack(global.DB, trackID)
track, err := db.GetTrack(global.DB, trackID)
if err != nil {
fmt.Printf("Error rendering new track component for %s: %s\n", trackID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -18,8 +18,8 @@ input[type="text"] {
.release-artwork {
width: 200px;
text-align: center;
}
.release-artwork img {
width: 100%;
aspect-ratio: 1;
@ -28,6 +28,9 @@ input[type="text"] {
outline: 1px solid #808080;
cursor: pointer;
}
.release-artwork #remove-artwork {
padding: .3em .4em;
}
.release-info {
width: 0;
@ -342,7 +345,7 @@ dialog div.dialog-actions {
background-color: #8cff83
}
.card.links a.button[data-name="applemusic"] {
.card.links a.button[data-name="apple music"] {
background-color: #8cd9ff
}

View file

@ -3,45 +3,36 @@ import Stateful from "/script/silver.min.js"
const releaseID = document.getElementById("release").dataset.id;
const titleInput = document.getElementById("title");
const artworkImg = document.getElementById("artwork");
const removeArtworkBtn = document.getElementById("remove-artwork");
const artworkInput = document.getElementById("artwork-file");
const typeInput = document.getElementById("type");
const descInput = document.getElementById("description");
const dateInput = document.getElementById("release-date");
const buynameInput = document.getElementById("buyname");
const buylinkInput = document.getElementById("buylink");
const copyrightInput = document.getElementById("copyright");
const copyrightURLInput = document.getElementById("copyright-url");
const visInput = document.getElementById("visibility");
const saveBtn = document.getElementById("save");
const deleteBtn = document.getElementById("delete");
var artworkData = artworkImg.attributes.src.value;
var edited = new Stateful(false);
var releaseData = updateData(undefined);
function updateData(old) {
var releaseData = {
visible: visInput.value === "true",
title: titleInput.value,
description: descInput.value,
type: typeInput.value,
releaseDate: dateInput.value,
artwork: artworkData,
buyname: buynameInput.value,
buylink: buylinkInput.value,
};
if (releaseData && releaseData != old) {
edited.set(true);
}
return releaseData;
}
function saveRelease() {
console.table(releaseData);
saveBtn.addEventListener("click", () => {
fetch("/api/v1/music/" + releaseID, {
method: "PUT",
body: JSON.stringify(releaseData),
body: JSON.stringify({
visible: visInput.value === "true",
title: titleInput.value,
description: descInput.value,
type: typeInput.value,
releaseDate: dateInput.value + ":00Z",
artwork: artworkData,
buyname: buynameInput.value,
buylink: buylinkInput.value,
copyright: copyrightInput.value,
copyrightURL: copyrightURLInput.value,
}),
headers: { "Content-Type": "application/json" }
}).then(res => {
if (!res.ok) {
@ -54,9 +45,13 @@ function saveRelease() {
location = location;
});
}
});
function deleteRelease() {
deleteBtn.addEventListener("click", () => {
if (releaseID != prompt(
"You are about to permanently delete " + releaseID + ". " +
"This action is irreversible. " +
"Please enter \"" + releaseID + "\" to continue.")) return;
fetch("/api/v1/music/" + releaseID, {
method: "DELETE",
}).then(res => {
@ -70,15 +65,17 @@ function deleteRelease() {
location = "/admin";
});
}
edited.onUpdate(edited => {
saveBtn.disabled = !edited;
})
titleInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
[titleInput, typeInput, descInput, dateInput, buynameInput, buylinkInput, copyrightInput, copyrightURLInput, visInput].forEach(input => {
input.addEventListener("change", () => {
saveBtn.disabled = false;
});
input.addEventListener("keypress", () => {
saveBtn.disabled = false;
});
});
artworkImg.addEventListener("click", () => {
artworkInput.addEventListener("change", () => {
if (artworkInput.files.length > 0) {
@ -87,41 +84,17 @@ artworkImg.addEventListener("click", () => {
const data = e.target.result;
artworkImg.src = data;
artworkData = data;
releaseData = updateData(releaseData);
saveBtn.disabled = false;
};
reader.readAsDataURL(artworkInput.files[0]);
}
});
artworkInput.click();
});
typeInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
descInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
dateInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
buynameInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
buylinkInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
visInput.addEventListener("change", () => {
releaseData = updateData(releaseData);
});
saveBtn.addEventListener("click", () => {
if (!edited.get()) return;
saveRelease();
});
deleteBtn.addEventListener("click", () => {
if (releaseID != prompt(
"You are about to permanently delete " + releaseID + ". " +
"This action is irreversible. " +
"Please enter \"" + releaseID + "\" to continue.")) return;
deleteRelease();
removeArtworkBtn.addEventListener("click", () => {
artworkImg.src = "/img/default-cover-art.png"
artworkData = "";
saveBtn.disabled = false;
});

View file

@ -25,7 +25,7 @@ func serveTrack() http.Handler {
return
}
dbReleases, err := music.GetTrackReleases(global.DB, track)
dbReleases, err := music.GetTrackReleases(global.DB, track.ID)
if err != nil {
fmt.Printf("Error rendering admin track page for %s: %s\n", id, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -33,7 +33,7 @@ func serveTrack() http.Handler {
}
releases := []model.FullRelease{}
for _, release := range dbReleases {
fullRelease, err := music.GetFullRelease(global.DB, release)
fullRelease, err := music.GetFullRelease(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to pull full release data for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -12,10 +12,11 @@
<div class="release-artwork">
<img src="{{.Artwork}}" alt="" width="256" loading="lazy" id="artwork">
<input type="file" id="artwork-file" name="Artwork" accept=".png,.jpg,.jpeg" hidden>
<button id="remove-artwork">Remove</button>
</div>
<div class="release-info">
<h1 class="release-title">
<input type="text" id="title" name="Title" value="{{.Title}}">
<input type="text" id="title" name="Title" value="{{.Title}}" autocomplete="true">
</h1>
<table>
<tr>
@ -53,19 +54,31 @@
<tr>
<td>Release Date</td>
<td>
<input type="datetime-local" name="Release Date" id="release-date" value="{{.TextReleaseDate}}">
<input type="datetime-local" name="release-date" id="release-date" value="{{.TextReleaseDate}}">
</td>
</tr>
<tr>
<td>Buy Name</td>
<td>
<input type="text" name="Buy Name" id="buyname" value="{{.Buyname}}">
<input type="text" name="buyname" id="buyname" value="{{.Buyname}}" autocomplete="true">
</td>
</tr>
<tr>
<td>Buy Link</td>
<td>
<input type="text" name="Buy Link" id="buylink" value="{{.Buylink}}">
<input type="text" name="buylink" id="buylink" value="{{.Buylink}}" autocomplete="true">
</td>
</tr>
<tr>
<td>Copyright</td>
<td>
<input type="text" name="copyright" id="copyright" value="{{.Copyright}}" autocomplete="true">
</td>
</tr>
<tr>
<td>Copyright URL</td>
<td>
<input type="text" name="copyright-url" id="copyright-url" value="{{.CopyrightURL}}" autocomplete="true">
</td>
</tr>
<tr>