2024-08-03 00:27:30 +01:00
|
|
|
package api
|
|
|
|
|
|
|
|
|
|
import (
|
2026-07-31 02:43:45 +01:00
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
2024-08-03 00:27:30 +01:00
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
"arimelody-web/errors"
|
2026-07-31 02:43:45 +01:00
|
|
|
"arimelody-web/model"
|
|
|
|
|
"arimelody-web/model/app"
|
2024-08-03 00:27:30 +01:00
|
|
|
)
|
|
|
|
|
|
2024-09-02 00:15:23 +01:00
|
|
|
type (
|
|
|
|
|
Track struct {
|
2024-09-03 08:07:45 +01:00
|
|
|
*model.Track
|
|
|
|
|
Releases []string `json:"releases"`
|
2024-09-02 00:15:23 +01:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2026-07-31 02:43:45 +01:00
|
|
|
func ServeAllTracks(app *app.AppState) http.Handler {
|
2024-08-03 23:24:15 +01:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2024-09-02 00:15:23 +01:00
|
|
|
type Track struct {
|
2024-09-01 04:43:32 +01:00
|
|
|
ID string `json:"id"`
|
|
|
|
|
Title string `json:"title"`
|
|
|
|
|
}
|
2024-09-02 00:15:23 +01:00
|
|
|
var tracks = []Track{}
|
2024-09-01 04:43:32 +01:00
|
|
|
|
2024-09-02 00:15:23 +01:00
|
|
|
var dbTracks = []*model.Track{}
|
2026-08-01 00:29:31 +01:00
|
|
|
dbTracks, err := app.MusicService.GetAllTracks()
|
2024-09-01 04:43:32 +01:00
|
|
|
if err != nil {
|
2025-01-20 15:08:01 +00:00
|
|
|
fmt.Printf("WARN: Failed to pull tracks from DB: %s\n", err)
|
2025-04-29 23:25:32 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
2024-09-01 04:43:32 +01:00
|
|
|
}
|
2024-08-03 23:24:15 +01:00
|
|
|
|
2024-09-02 00:15:23 +01:00
|
|
|
for _, track := range dbTracks {
|
|
|
|
|
tracks = append(tracks, Track{
|
|
|
|
|
ID: track.ID,
|
|
|
|
|
Title: track.Title,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-29 23:25:32 +01:00
|
|
|
w.Header().Add("Content-Type", "application/json")
|
2024-12-02 12:47:42 +00:00
|
|
|
encoder := json.NewEncoder(w)
|
|
|
|
|
encoder.SetIndent("", "\t")
|
|
|
|
|
err = encoder.Encode(tracks)
|
2025-04-29 23:25:32 +01:00
|
|
|
if err != nil {
|
2025-01-20 15:08:01 +00:00
|
|
|
fmt.Printf("WARN: Failed to serve all tracks: %s\n", err)
|
2025-04-29 23:25:32 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
|
|
}
|
2024-08-03 23:24:15 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-31 02:43:45 +01:00
|
|
|
func ServeTrack(app *app.AppState, track *model.Track) http.Handler {
|
2025-04-29 23:25:32 +01:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2026-08-01 00:29:31 +01:00
|
|
|
dbReleases, err := app.MusicService.GetTrackReleases(track.ID)
|
2024-09-01 04:43:32 +01:00
|
|
|
if err != nil {
|
2025-01-20 15:08:01 +00:00
|
|
|
fmt.Printf("WARN: Failed to pull track releases for %s from DB: %s\n", track.ID, err)
|
2025-04-29 23:25:32 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
2024-09-01 04:43:32 +01:00
|
|
|
}
|
2024-09-03 08:07:45 +01:00
|
|
|
|
|
|
|
|
releases := []string{}
|
|
|
|
|
for _, release := range dbReleases {
|
|
|
|
|
releases = append(releases, release.ID)
|
|
|
|
|
}
|
2024-09-01 04:43:32 +01:00
|
|
|
|
2025-04-29 23:25:32 +01:00
|
|
|
w.Header().Add("Content-Type", "application/json")
|
2024-12-02 12:47:42 +00:00
|
|
|
encoder := json.NewEncoder(w)
|
|
|
|
|
encoder.SetIndent("", "\t")
|
|
|
|
|
err = encoder.Encode(Track{ track, releases })
|
2025-04-29 23:25:32 +01:00
|
|
|
if err != nil {
|
2025-01-20 15:08:01 +00:00
|
|
|
fmt.Printf("WARN: Failed to serve track %s: %s\n", track.ID, err)
|
2025-04-29 23:25:32 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
|
|
}
|
|
|
|
|
})
|
2024-08-03 23:24:15 +01:00
|
|
|
}
|
|
|
|
|
|
2026-07-31 02:43:45 +01:00
|
|
|
func CreateTrack(app *app.AppState) http.Handler {
|
2024-08-03 00:27:30 +01:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2025-02-07 16:40:58 +00:00
|
|
|
session := r.Context().Value("session").(*model.Session)
|
2024-08-03 00:27:30 +01:00
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
type CreateTrackDTO struct {
|
|
|
|
|
Title string `json:"title"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Lyrics string `json:"lyrics"`
|
|
|
|
|
}
|
|
|
|
|
var dto CreateTrackDTO
|
|
|
|
|
err := json.NewDecoder(r.Body).Decode(&dto)
|
2024-08-03 00:27:30 +01:00
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
id, err := app.MusicService.CreateTrack(dto.Title, dto.Description, dto.Lyrics, "")
|
2024-08-03 00:27:30 +01:00
|
|
|
if err != nil {
|
2026-08-01 00:29:31 +01:00
|
|
|
if errors.IsValidationError(err) {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-01-20 15:08:01 +00:00
|
|
|
fmt.Printf("WARN: Failed to create track: %s\n", err)
|
2024-08-03 00:27:30 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
app.LogService.Info(model.LOG_MUSIC, "Track \"%s\" (%s) created by \"%s\".", dto.Title, id, session.Account.Username)
|
2025-02-07 16:40:58 +00:00
|
|
|
|
2024-09-01 04:43:32 +01:00
|
|
|
w.Header().Add("Content-Type", "text/plain")
|
2024-08-03 00:27:30 +01:00
|
|
|
w.WriteHeader(http.StatusCreated)
|
2024-09-02 00:15:23 +01:00
|
|
|
w.Write([]byte(id))
|
2024-08-03 00:27:30 +01:00
|
|
|
})
|
|
|
|
|
}
|
2024-08-03 23:24:15 +01:00
|
|
|
|
2026-07-31 02:43:45 +01:00
|
|
|
func UpdateTrack(app *app.AppState, track *model.Track) http.Handler {
|
2024-08-03 23:24:15 +01:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2025-02-07 16:40:58 +00:00
|
|
|
if r.URL.Path == "/" {
|
2024-08-03 23:24:15 +01:00
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 16:40:58 +00:00
|
|
|
session := r.Context().Value("session").(*model.Session)
|
|
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
type UpdateTrackDTO struct {
|
|
|
|
|
Title string `json:"title"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Lyrics string `json:"lyrics"`
|
|
|
|
|
}
|
|
|
|
|
var dto UpdateTrackDTO
|
|
|
|
|
err := json.NewDecoder(r.Body).Decode(&dto)
|
2024-08-03 23:24:15 +01:00
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
track.Title = dto.Title
|
|
|
|
|
track.Description = dto.Description
|
|
|
|
|
track.Lyrics = dto.Lyrics
|
2024-08-03 23:24:15 +01:00
|
|
|
|
2026-08-01 00:29:31 +01:00
|
|
|
err = app.MusicService.UpdateTrack(track)
|
2024-08-03 23:24:15 +01:00
|
|
|
if err != nil {
|
2026-08-01 00:29:31 +01:00
|
|
|
if errors.IsValidationError(err) {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-01-21 00:20:07 +00:00
|
|
|
fmt.Printf("WARN: Failed to update track %s: %s\n", track.ID, err)
|
2024-08-03 23:24:15 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-31 10:02:34 +01:00
|
|
|
app.LogService.Info(model.LOG_MUSIC, "Track \"%s\" (%s) updated by \"%s\".", track.Title, track.ID, session.Account.Username)
|
2025-02-07 16:40:58 +00:00
|
|
|
|
2024-08-03 23:24:15 +01:00
|
|
|
w.Header().Add("Content-Type", "application/json")
|
2024-12-02 12:47:42 +00:00
|
|
|
encoder := json.NewEncoder(w)
|
|
|
|
|
encoder.SetIndent("", "\t")
|
|
|
|
|
err = encoder.Encode(track)
|
2024-08-03 23:24:15 +01:00
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-31 02:43:45 +01:00
|
|
|
func DeleteTrack(app *app.AppState, track *model.Track) http.Handler {
|
2024-08-03 23:24:15 +01:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2025-02-07 16:40:58 +00:00
|
|
|
if r.URL.Path == "/" {
|
2024-08-03 23:24:15 +01:00
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 16:40:58 +00:00
|
|
|
session := r.Context().Value("session").(*model.Session)
|
|
|
|
|
|
2024-08-03 23:24:15 +01:00
|
|
|
var trackID = r.URL.Path[1:]
|
2026-08-01 00:29:31 +01:00
|
|
|
err := app.MusicService.DeleteTrack(trackID)
|
2024-08-03 23:24:15 +01:00
|
|
|
if err != nil {
|
2026-08-01 00:29:31 +01:00
|
|
|
if errors.IsNotExistError(err) {
|
|
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-01-21 00:20:07 +00:00
|
|
|
fmt.Printf("WARN: Failed to delete track %s: %s\n", trackID, err)
|
2024-08-03 23:24:15 +01:00
|
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
|
|
}
|
2025-02-07 16:40:58 +00:00
|
|
|
|
2026-07-31 10:02:34 +01:00
|
|
|
app.LogService.Info(model.LOG_MUSIC, "Track \"%s\" (%s) deleted by \"%s\".", track.Title, track.ID, session.Account.Username)
|
2024-08-03 23:24:15 +01:00
|
|
|
})
|
|
|
|
|
}
|