refactor mux path routes
legend has it that if you refactor your code enough times, one day you will finally be happy
This commit is contained in:
parent
82fd17c836
commit
21912d4ec2
17 changed files with 102 additions and 469 deletions
|
|
@ -17,18 +17,20 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Handler(app *model.AppState) http.Handler {
|
func Handler(app *model.AppState) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
mux.Handle("/", accountIndexHandler(app))
|
mux.Handle("/", accountIndexHandler(app))
|
||||||
|
|
||||||
mux.Handle("/account/totp-setup", totpSetupHandler(app))
|
mux.Handle("/totp-setup", totpSetupHandler(app))
|
||||||
mux.Handle("/account/totp-confirm", totpConfirmHandler(app))
|
mux.Handle("/totp-confirm", totpConfirmHandler(app))
|
||||||
mux.Handle("/account/totp-delete", http.StripPrefix("/totp-delete", totpDeleteHandler(app)))
|
mux.Handle("/totp-delete", totpDeleteHandler(app))
|
||||||
|
|
||||||
mux.Handle("/account/password", changePasswordHandler(app))
|
mux.Handle("/password", changePasswordHandler(app))
|
||||||
mux.Handle("/account/delete", deleteAccountHandler(app))
|
mux.Handle("/delete", deleteAccountHandler(app))
|
||||||
|
|
||||||
return mux
|
mux.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func accountIndexHandler(app *model.AppState) http.Handler {
|
func accountIndexHandler(app *model.AppState) http.Handler {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"arimelody-web/admin/core"
|
"arimelody-web/admin/core"
|
||||||
"arimelody-web/admin/templates"
|
"arimelody-web/admin/templates"
|
||||||
|
|
@ -16,14 +15,6 @@ func serveArtists(app *model.AppState) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
session := r.Context().Value("session").(*model.Session)
|
session := r.Context().Value("session").(*model.Session)
|
||||||
|
|
||||||
slices := strings.Split(strings.TrimPrefix(r.URL.Path, "/artists")[1:], "/")
|
|
||||||
artistID := slices[0]
|
|
||||||
|
|
||||||
if len(artistID) > 0 {
|
|
||||||
serveArtist(app, artistID).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
artists, err := controller.GetAllArtists(app.DB)
|
artists, err := controller.GetAllArtists(app.DB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "WARN: Failed to fetch artists: %s\n", err)
|
fmt.Fprintf(os.Stderr, "WARN: Failed to fetch artists: %s\n", err)
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,17 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
mux.Handle("/releases/", serveReleases(app))
|
mux.Handle("/releases/", http.StripPrefix("/releases", serveReleases(app)))
|
||||||
mux.Handle("/artists/", serveArtists(app))
|
|
||||||
mux.Handle("/tracks/", serveTracks(app))
|
mux.HandleFunc("/artists/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
serveArtist(app, r.PathValue("id")).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
mux.Handle("/artists/", http.StripPrefix("/artists", serveArtists(app)))
|
||||||
|
|
||||||
|
mux.HandleFunc("/tracks/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
serveTrack(app, r.PathValue("id")).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
mux.Handle("/tracks/", http.StripPrefix("/tracks", serveTracks(app)))
|
||||||
|
|
||||||
mux.ServeHTTP(w, r)
|
mux.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -13,21 +13,42 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func serveReleases(app *model.AppState) http.Handler {
|
func serveReleases(app *model.AppState) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux := http.NewServeMux()
|
||||||
session := r.Context().Value("session").(*model.Session)
|
|
||||||
|
|
||||||
slices := strings.Split(strings.TrimPrefix(r.URL.Path, "/releases")[1:], "/")
|
mux.HandleFunc("/{id}/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
releaseID := slices[0]
|
releaseID := r.PathValue("id")
|
||||||
|
release, err := controller.GetRelease(app.DB, releaseID, true)
|
||||||
var action string = ""
|
if err != nil {
|
||||||
if len(slices) > 1 {
|
if strings.Contains(err.Error(), "no rows") {
|
||||||
action = slices[1]
|
http.NotFound(w, r)
|
||||||
}
|
|
||||||
|
|
||||||
if len(releaseID) > 0 {
|
|
||||||
serveRelease(app, releaseID, action).ServeHTTP(w, r)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "WARN: Failed to fetch full release data for %s: %s\n", releaseID, err)
|
||||||
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
mux.Handle("/{id}/editcredits", serveEditCredits(release))
|
||||||
|
mux.Handle("/{id}/addcredit", serveAddCredit(app, release))
|
||||||
|
mux.Handle("/{id}/newcredit", serveNewCredit(app))
|
||||||
|
|
||||||
|
mux.Handle("/{id}/editlinks", serveEditLinks(release))
|
||||||
|
|
||||||
|
mux.Handle("/{id}/edittracks", serveEditTracks(release))
|
||||||
|
mux.Handle("/{id}/addtrack", serveAddTrack(app, release))
|
||||||
|
mux.Handle("/{id}/newtrack", serveNewTrack(app))
|
||||||
|
|
||||||
|
mux.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.HandleFunc("/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
serveRelease(app, r.PathValue("id")).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
session := r.Context().Value("session").(*model.Session)
|
||||||
|
|
||||||
type ReleasesData struct {
|
type ReleasesData struct {
|
||||||
core.AdminPageData
|
core.AdminPageData
|
||||||
|
|
@ -54,9 +75,11 @@ func serveReleases(app *model.AppState) http.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return mux
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveRelease(app *model.AppState, releaseID string, action string) http.Handler {
|
func serveRelease(app *model.AppState, releaseID string) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
session := r.Context().Value("session").(*model.Session)
|
session := r.Context().Value("session").(*model.Session)
|
||||||
|
|
||||||
|
|
@ -71,34 +94,6 @@ func serveRelease(app *model.AppState, releaseID string, action string) http.Han
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(action) > 0 {
|
|
||||||
switch action {
|
|
||||||
case "editcredits":
|
|
||||||
serveEditCredits(release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "addcredit":
|
|
||||||
serveAddCredit(app, release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "newcredit":
|
|
||||||
serveNewCredit(app).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "editlinks":
|
|
||||||
serveEditLinks(release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "edittracks":
|
|
||||||
serveEditTracks(release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "addtrack":
|
|
||||||
serveAddTrack(app, release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "newtrack":
|
|
||||||
serveNewTrack(app).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReleaseResponse struct {
|
type ReleaseResponse struct {
|
||||||
core.AdminPageData
|
core.AdminPageData
|
||||||
Release *model.Release
|
Release *model.Release
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"arimelody-web/admin/core"
|
"arimelody-web/admin/core"
|
||||||
"arimelody-web/admin/templates"
|
"arimelody-web/admin/templates"
|
||||||
|
|
@ -16,14 +15,6 @@ func serveTracks(app *model.AppState) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
session := r.Context().Value("session").(*model.Session)
|
session := r.Context().Value("session").(*model.Session)
|
||||||
|
|
||||||
slices := strings.Split(strings.TrimPrefix(r.URL.Path, "/tracks")[1:], "/")
|
|
||||||
trackID := slices[0]
|
|
||||||
|
|
||||||
if len(trackID) > 0 {
|
|
||||||
serveTrack(app, trackID).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tracks, err := controller.GetAllTracks(app.DB)
|
tracks, err := controller.GetAllTracks(app.DB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "WARN: Failed to fetch tracks: %s\n", err)
|
fmt.Fprintf(os.Stderr, "WARN: Failed to fetch tracks: %s\n", err)
|
||||||
|
|
|
||||||
|
|
@ -1,256 +0,0 @@
|
||||||
package admin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"arimelody-web/admin/core"
|
|
||||||
"arimelody-web/admin/templates"
|
|
||||||
"arimelody-web/controller"
|
|
||||||
"arimelody-web/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func serveReleases(app *model.AppState) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
session := r.Context().Value("session").(*model.Session)
|
|
||||||
|
|
||||||
slices := strings.Split(strings.TrimPrefix(r.URL.Path, "/releases")[1:], "/")
|
|
||||||
releaseID := slices[0]
|
|
||||||
|
|
||||||
var action string = ""
|
|
||||||
if len(slices) > 1 {
|
|
||||||
action = slices[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(releaseID) > 0 {
|
|
||||||
serveRelease(app, releaseID, action).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReleasesData struct {
|
|
||||||
core.AdminPageData
|
|
||||||
Releases []*model.Release
|
|
||||||
}
|
|
||||||
|
|
||||||
releases, err := controller.GetAllReleases(app.DB, false, 0, true)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "WARN: Failed to fetch releases: %s\n", err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = templates.ReleasesTemplate.Execute(w, ReleasesData{
|
|
||||||
AdminPageData: core.AdminPageData{
|
|
||||||
Path: r.URL.Path,
|
|
||||||
Session: session,
|
|
||||||
},
|
|
||||||
Releases: releases,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "WARN: Failed to serve releases page: %s\n", err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveRelease(app *model.AppState, releaseID string, action string) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
session := r.Context().Value("session").(*model.Session)
|
|
||||||
|
|
||||||
release, err := controller.GetRelease(app.DB, releaseID, true)
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "no rows") {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("WARN: Failed to fetch full release data for %s: %s\n", releaseID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(action) > 0 {
|
|
||||||
switch action {
|
|
||||||
case "editcredits":
|
|
||||||
serveEditCredits(release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "addcredit":
|
|
||||||
serveAddCredit(app, release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "newcredit":
|
|
||||||
serveNewCredit(app).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "editlinks":
|
|
||||||
serveEditLinks(release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "edittracks":
|
|
||||||
serveEditTracks(release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "addtrack":
|
|
||||||
serveAddTrack(app, release).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
case "newtrack":
|
|
||||||
serveNewTrack(app).ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReleaseResponse struct {
|
|
||||||
core.AdminPageData
|
|
||||||
Release *model.Release
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, track := range release.Tracks { track.Number = i + 1 }
|
|
||||||
|
|
||||||
err = templates.EditReleaseTemplate.Execute(w, ReleaseResponse{
|
|
||||||
AdminPageData: core.AdminPageData{ Path: r.URL.Path, Session: session },
|
|
||||||
Release: release,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve admin release page for %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveEditCredits(release *model.Release) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
err := templates.EditCreditsTemplate.Execute(w, release)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve edit credits component for %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveAddCredit(app *model.AppState, release *model.Release) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
artists, err := controller.GetArtistsNotOnRelease(app.DB, release.ID)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to fetch artists not on %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type response struct {
|
|
||||||
ReleaseID string;
|
|
||||||
Artists []*model.Artist
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
err = templates.AddCreditTemplate.Execute(w, response{
|
|
||||||
ReleaseID: release.ID,
|
|
||||||
Artists: artists,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve add credits component for %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveNewCredit(app *model.AppState) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
split := strings.Split(r.URL.Path, "/")
|
|
||||||
artistID := split[len(split) - 1]
|
|
||||||
artist, err := controller.GetArtist(app.DB, artistID)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to fetch artist %s: %s\n", artistID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if artist == nil {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
err = templates.NewCreditTemplate.Execute(w, artist)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve new credit component for %s: %s\n", artist.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveEditLinks(release *model.Release) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
err := templates.EditLinksTemplate.Execute(w, release)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve edit links component for %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveEditTracks(release *model.Release) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
|
|
||||||
type editTracksData struct { Release *model.Release }
|
|
||||||
|
|
||||||
for i, track := range release.Tracks { track.Number = i + 1 }
|
|
||||||
|
|
||||||
err := templates.EditTracksTemplate.Execute(w, editTracksData{ Release: release })
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve edit tracks component for %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveAddTrack(app *model.AppState, release *model.Release) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
tracks, err := controller.GetTracksNotOnRelease(app.DB, release.ID)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to fetch tracks not on %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type response struct {
|
|
||||||
ReleaseID string;
|
|
||||||
Tracks []*model.Track
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
err = templates.AddTrackTemplate.Execute(w, response{
|
|
||||||
ReleaseID: release.ID,
|
|
||||||
Tracks: tracks,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to add tracks component for %s: %s\n", release.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveNewTrack(app *model.AppState) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
split := strings.Split(r.URL.Path, "/")
|
|
||||||
trackID := split[len(split) - 1]
|
|
||||||
track, err := controller.GetTrack(app.DB, trackID)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to fetch track %s: %s\n", trackID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if track == nil {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
err = templates.NewTrackTemplate.Execute(w, track)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("WARN: Failed to serve new track component for %s: %s\n", track.ID, err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -18,7 +18,7 @@ document.addEventListener("readystatechange", () => {
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
res.text().then(text => {
|
res.text().then(text => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
location = "/admin/artists/" + id;
|
location = "/admin/music/artists/" + id;
|
||||||
} else {
|
} else {
|
||||||
alert(text);
|
alert(text);
|
||||||
console.error(text);
|
console.error(text);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ document.addEventListener('readystatechange', () => {
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({id})
|
body: JSON.stringify({id})
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.ok) location = "/admin/releases/" + id;
|
if (res.ok) location = "/admin/music/releases/" + id;
|
||||||
else {
|
else {
|
||||||
res.text().then(err => {
|
res.text().then(err => {
|
||||||
alert(err);
|
alert(err);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ if (newTrackBtn) newTrackBtn.addEventListener("click", event => {
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
res.text().then(text => {
|
res.text().then(text => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
location = "/admin/tracks/" + text;
|
location = "/admin/music/tracks/" + text;
|
||||||
} else {
|
} else {
|
||||||
alert(text);
|
alert(text);
|
||||||
console.error(text);
|
console.error(text);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="cards">
|
<div class="cards">
|
||||||
<div class="card" id="releases">
|
<div class="card" id="releases">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2><a href="/admin/releases/">Releases</a> <small>({{.ReleaseCount}} total)</small></h2>
|
<h2><a href="/admin/music/releases/">Releases</a> <small>({{.ReleaseCount}} total)</small></h2>
|
||||||
<a class="button new" id="create-release">Create New</a>
|
<a class="button new" id="create-release">Create New</a>
|
||||||
</div>
|
</div>
|
||||||
{{if .Artists}}
|
{{if .Artists}}
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
<div class="card" id="artists">
|
<div class="card" id="artists">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2><a href="/admin/artists/">Artists</a> <small>({{.ArtistCount}} total)</small></h2>
|
<h2><a href="/admin/music/artists/">Artists</a> <small>({{.ArtistCount}} total)</small></h2>
|
||||||
<a class="button new" id="create-artist">Create New</a>
|
<a class="button new" id="create-artist">Create New</a>
|
||||||
</div>
|
</div>
|
||||||
{{if .Artists}}
|
{{if .Artists}}
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
<div class="card" id="tracks">
|
<div class="card" id="tracks">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2><a href="/admin/tracks/">Tracks</a> <small>({{.TrackCount}} total)</small></h2>
|
<h2><a href="/admin/music/tracks/">Tracks</a> <small>({{.TrackCount}} total)</small></h2>
|
||||||
<a class="button new" id="create-track">Create New</a>
|
<a class="button new" id="create-track">Create New</a>
|
||||||
</div>
|
</div>
|
||||||
<p><em>"Orphaned" tracks that have not yet been bound to a release.</em></p>
|
<p><em>"Orphaned" tracks that have not yet been bound to a release.</em></p>
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@
|
||||||
<div class="flex-fill"></div>
|
<div class="flex-fill"></div>
|
||||||
|
|
||||||
{{if .Session.Account}}
|
{{if .Session.Account}}
|
||||||
<div class="nav-item{{if eq .Path "/account"}} active{{end}}">
|
<div class="nav-item{{if hasPrefix .Path "/account"}} active{{end}}">
|
||||||
<a href="/admin/account">account ({{.Session.Account.Username}})</a>
|
<a href="/admin/account/">account ({{.Session.Account.Username}})</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item">
|
<div class="nav-item">
|
||||||
<a href="/admin/logout" id="logout">log out</a>
|
<a href="/admin/logout" id="logout">log out</a>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
{{define "head"}}
|
|
||||||
<title>Admin - ari melody 💫</title>
|
|
||||||
<link rel="shortcut icon" href="/img/favicon.png" type="image/x-icon">
|
|
||||||
<link rel="stylesheet" href="/admin/static/index.css">
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "content"}}
|
|
||||||
<main>
|
|
||||||
<h1>Admin Dashboard</h1>
|
|
||||||
<div class="card-header">
|
|
||||||
<h2>Music</h2>
|
|
||||||
<a class="button" href="/admin/music/">Browse All</a>
|
|
||||||
</div>
|
|
||||||
<div class="card" id="music">
|
|
||||||
{{if .LatestRelease}}
|
|
||||||
<h3>Latest Release</h3>
|
|
||||||
{{block "release" .LatestRelease}}{{end}}
|
|
||||||
{{else}}
|
|
||||||
<p>There are no releases.</p>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script type="module" src="/admin/static/admin.js"></script>
|
|
||||||
<script type="module" src="/admin/static/index.js"></script>
|
|
||||||
{{end}}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
|
|
||||||
{{block "head" .}}{{end}}
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/admin/static/admin.css">
|
|
||||||
<script type="module" src="/script/vendor/htmx.min.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<div class="nav-item icon" title="return to user space">
|
|
||||||
<a href="/"><img src="/img/favicon.png" alt=""/></a>
|
|
||||||
</div>
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin">home</a>
|
|
||||||
</div>
|
|
||||||
{{if .Session.Account}}
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin/music/">music</a>
|
|
||||||
</div>
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin/blog">blog</a>
|
|
||||||
</div>
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin/logs">logs</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<div class="flex-fill"></div>
|
|
||||||
|
|
||||||
{{if .Session.Account}}
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin/account/">account ({{.Session.Account.Username}})</a>
|
|
||||||
</div>
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin/logout" id="logout">log out</a>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<div class="nav-item">
|
|
||||||
<a href="/admin/register" id="register">create account</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{{block "content" .}}{{end}}
|
|
||||||
|
|
||||||
{{template "prideflag"}}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
18
api/api.go
18
api/api.go
|
|
@ -18,8 +18,8 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
|
|
||||||
// ARTIST ENDPOINTS
|
// ARTIST ENDPOINTS
|
||||||
|
|
||||||
mux.Handle("/v1/artist/", http.StripPrefix("/v1/artist", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/v1/artist/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
var artistID = strings.Split(r.URL.Path[1:], "/")[0]
|
var artistID = r.PathValue("id")
|
||||||
artist, err := controller.GetArtist(app.DB, artistID)
|
artist, err := controller.GetArtist(app.DB, artistID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "no rows") {
|
if strings.Contains(err.Error(), "no rows") {
|
||||||
|
|
@ -44,7 +44,7 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
default:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
})))
|
}))
|
||||||
mux.Handle("/v1/artist", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/v1/artist", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
|
|
@ -60,8 +60,8 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
|
|
||||||
// RELEASE ENDPOINTS
|
// RELEASE ENDPOINTS
|
||||||
|
|
||||||
mux.Handle("/v1/music/", http.StripPrefix("/v1/music", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/v1/music/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
var releaseID = strings.Split(r.URL.Path[1:], "/")[0]
|
var releaseID = r.PathValue("id")
|
||||||
release, err := controller.GetRelease(app.DB, releaseID, true)
|
release, err := controller.GetRelease(app.DB, releaseID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "no rows") {
|
if strings.Contains(err.Error(), "no rows") {
|
||||||
|
|
@ -86,7 +86,7 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
default:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
})))
|
}))
|
||||||
mux.Handle("/v1/music", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/v1/music", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
|
|
@ -102,8 +102,8 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
|
|
||||||
// TRACK ENDPOINTS
|
// TRACK ENDPOINTS
|
||||||
|
|
||||||
mux.Handle("/v1/track/", http.StripPrefix("/v1/track", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/v1/track/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
var trackID = strings.Split(r.URL.Path[1:], "/")[0]
|
var trackID = r.PathValue("id")
|
||||||
track, err := controller.GetTrack(app.DB, trackID)
|
track, err := controller.GetTrack(app.DB, trackID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "no rows") {
|
if strings.Contains(err.Error(), "no rows") {
|
||||||
|
|
@ -128,7 +128,7 @@ func Handler(app *model.AppState) http.Handler {
|
||||||
default:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
})))
|
}))
|
||||||
mux.Handle("/v1/track", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/v1/track", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
|
|
|
||||||
24
main.go
24
main.go
|
|
@ -517,7 +517,15 @@ func main() {
|
||||||
go cursor.StartCursor(&app)
|
go cursor.StartCursor(&app)
|
||||||
|
|
||||||
// start the web server!
|
// start the web server!
|
||||||
mux := createServeMux(&app)
|
mux := http.NewServeMux()
|
||||||
|
mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler(&app)))
|
||||||
|
mux.Handle("/api/", http.StripPrefix("/api", api.Handler(&app)))
|
||||||
|
mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler(&app)))
|
||||||
|
mux.Handle("/blog/", http.StripPrefix("/blog", view.BlogHandler(&app)))
|
||||||
|
mux.Handle("/uploads/", http.StripPrefix("/uploads", view.ServeFiles(filepath.Join(app.Config.DataDirectory, "uploads"))))
|
||||||
|
mux.Handle("/cursor-ws", cursor.Handler(&app))
|
||||||
|
mux.Handle("/", view.IndexHandler(&app))
|
||||||
|
|
||||||
fmt.Printf("Now serving at http://%s:%d\n", app.Config.Host, app.Config.Port)
|
fmt.Printf("Now serving at http://%s:%d\n", app.Config.Host, app.Config.Port)
|
||||||
stdLog.Fatal(
|
stdLog.Fatal(
|
||||||
http.ListenAndServe(fmt.Sprintf("%s:%d", app.Config.Host, app.Config.Port),
|
http.ListenAndServe(fmt.Sprintf("%s:%d", app.Config.Host, app.Config.Port),
|
||||||
|
|
@ -525,20 +533,6 @@ func main() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createServeMux(app *model.AppState) *http.ServeMux {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
|
|
||||||
mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler(app)))
|
|
||||||
mux.Handle("/api/", http.StripPrefix("/api", api.Handler(app)))
|
|
||||||
mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler(app)))
|
|
||||||
mux.Handle("/blog/", http.StripPrefix("/blog", view.BlogHandler(app)))
|
|
||||||
mux.Handle("/uploads/", http.StripPrefix("/uploads", view.ServeFiles(filepath.Join(app.Config.DataDirectory, "uploads"))))
|
|
||||||
mux.Handle("/cursor-ws", cursor.Handler(app))
|
|
||||||
mux.Handle("/", view.IndexHandler(app))
|
|
||||||
|
|
||||||
return mux
|
|
||||||
}
|
|
||||||
|
|
||||||
var PoweredByStrings = []string{
|
var PoweredByStrings = []string{
|
||||||
"nerd rage",
|
"nerd rage",
|
||||||
"estrogen",
|
"estrogen",
|
||||||
|
|
|
||||||
16
view/blog.go
16
view/blog.go
|
|
@ -44,17 +44,13 @@ var mdRenderer = html.NewRenderer(html.RendererOptions{
|
||||||
})
|
})
|
||||||
|
|
||||||
func BlogHandler(app *model.AppState) http.Handler {
|
func BlogHandler(app *model.AppState) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux := http.NewServeMux()
|
||||||
if strings.Count(r.URL.Path, "/") > 1 {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.URL.Path) > 1 {
|
mux.HandleFunc("/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
ServeBlogPost(app, r.URL.Path[1:]).ServeHTTP(w, r)
|
ServeBlogPost(app, r.PathValue("id")).ServeHTTP(w, r)
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
dbPosts, err := controller.GetBlogPosts(app.DB, true, -1, 0)
|
dbPosts, err := controller.GetBlogPosts(app.DB, true, -1, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "no rows") {
|
if strings.Contains(err.Error(), "no rows") {
|
||||||
|
|
@ -111,6 +107,8 @@ func BlogHandler(app *model.AppState) http.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return mux
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServeBlogPost(app *model.AppState, blogPostID string) http.Handler {
|
func ServeBlogPost(app *model.AppState, blogPostID string) http.Handler {
|
||||||
|
|
|
||||||
|
|
@ -15,20 +15,10 @@ import (
|
||||||
func MusicHandler(app *model.AppState) http.Handler {
|
func MusicHandler(app *model.AppState) http.Handler {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/" {
|
ServeGateway(app, r.PathValue("id")).ServeHTTP(w, r)
|
||||||
ServeCatalog(app).ServeHTTP(w, r)
|
})
|
||||||
return
|
mux.Handle("/", ServeCatalog(app))
|
||||||
}
|
|
||||||
|
|
||||||
release, err := controller.GetRelease(app.DB, r.URL.Path[1:], true)
|
|
||||||
if err != nil {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ServeGateway(app, release).ServeHTTP(w, r)
|
|
||||||
}))
|
|
||||||
|
|
||||||
return mux
|
return mux
|
||||||
}
|
}
|
||||||
|
|
@ -55,8 +45,14 @@ func ServeCatalog(app *model.AppState) http.Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServeGateway(app *model.AppState, release *model.Release) http.Handler {
|
func ServeGateway(app *model.AppState, releaseID string) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
release, err := controller.GetRelease(app.DB, r.PathValue("id"), true)
|
||||||
|
if err != nil {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// only allow authorised users to view hidden releases
|
// only allow authorised users to view hidden releases
|
||||||
privileged := false
|
privileged := false
|
||||||
if !release.Visible {
|
if !release.Visible {
|
||||||
|
|
@ -86,8 +82,7 @@ func ServeGateway(app *model.AppState, release *model.Release) http.Handler {
|
||||||
|
|
||||||
for i, track := range release.Tracks { track.Number = i + 1 }
|
for i, track := range release.Tracks { track.Number = i + 1 }
|
||||||
|
|
||||||
err := templates.MusicGatewayTemplate.Execute(w, release)
|
err = templates.MusicGatewayTemplate.Execute(w, release)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error rendering music gateway for %s: %v\n", release.ID, err)
|
fmt.Fprintf(os.Stderr, "Error rendering music gateway for %s: %v\n", release.ID, err)
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue