+108
cmd/handlers.go
+108
cmd/handlers.go
···
1
1
package main
2
2
3
3
import (
4
+
"encoding/json"
4
5
"fmt"
5
6
"log"
6
7
"net/http"
···
308
309
jsonResponse(w, http.StatusOK, recordings)
309
310
}
310
311
}
312
+
313
+
func apiMeHandler(database *db.DB) http.HandlerFunc {
314
+
return func(w http.ResponseWriter, r *http.Request) {
315
+
userID, authenticated := session.GetUserID(r.Context())
316
+
if !authenticated {
317
+
jsonResponse(w, http.StatusUnauthorized, map[string]any{"authenticated": false, "error": "Unauthorized"})
318
+
return
319
+
}
320
+
321
+
user, err := database.GetUserByID(userID)
322
+
if err != nil {
323
+
log.Printf("apiMeHandler: Error fetching user %d: %v", userID, err)
324
+
jsonResponse(w, http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
325
+
return
326
+
}
327
+
if user == nil {
328
+
jsonResponse(w, http.StatusNotFound, map[string]string{"error": "User not found"})
329
+
return
330
+
}
331
+
332
+
lastfmUsername := ""
333
+
if user.LastFMUsername != nil {
334
+
lastfmUsername = *user.LastFMUsername
335
+
}
336
+
337
+
spotifyConnected := user.SpotifyID != nil
338
+
339
+
response := map[string]any{
340
+
"authenticated": true,
341
+
"user_id": user.ID,
342
+
"did": user.ATProtoDID,
343
+
"lastfm_username": lastfmUsername,
344
+
"spotify_connected": spotifyConnected,
345
+
}
346
+
if user.LastFMUsername == nil {
347
+
response["lastfm_username"] = nil
348
+
}
349
+
350
+
jsonResponse(w, http.StatusOK, response)
351
+
}
352
+
}
353
+
354
+
func apiGetLastfmUserHandler(database *db.DB) http.HandlerFunc {
355
+
return func(w http.ResponseWriter, r *http.Request) {
356
+
userID, _ := session.GetUserID(r.Context()) // Auth middleware ensures user is present
357
+
user, err := database.GetUserByID(userID)
358
+
if err != nil {
359
+
log.Printf("apiGetLastfmUserHandler: Error fetching user %d: %v", userID, err)
360
+
jsonResponse(w, http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
361
+
return
362
+
}
363
+
if user == nil {
364
+
jsonResponse(w, http.StatusNotFound, map[string]string{"error": "User not found"})
365
+
return
366
+
}
367
+
368
+
var lastfmUsername *string
369
+
if user.LastFMUsername != nil {
370
+
lastfmUsername = user.LastFMUsername
371
+
}
372
+
jsonResponse(w, http.StatusOK, map[string]*string{"lastfm_username": lastfmUsername})
373
+
}
374
+
}
375
+
376
+
func apiLinkLastfmHandler(database *db.DB) http.HandlerFunc {
377
+
return func(w http.ResponseWriter, r *http.Request) {
378
+
userID, _ := session.GetUserID(r.Context())
379
+
380
+
var reqBody struct {
381
+
LastFMUsername string `json:"lastfm_username"`
382
+
}
383
+
if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil {
384
+
jsonResponse(w, http.StatusBadRequest, map[string]string{"error": "Invalid request body: " + err.Error()})
385
+
return
386
+
}
387
+
388
+
if reqBody.LastFMUsername == "" {
389
+
jsonResponse(w, http.StatusBadRequest, map[string]string{"error": "Last.fm username cannot be empty"})
390
+
return
391
+
}
392
+
393
+
err := database.AddLastFMUsername(userID, reqBody.LastFMUsername)
394
+
if err != nil {
395
+
log.Printf("apiLinkLastfmHandler: Error saving Last.fm username for user %d: %v", userID, err)
396
+
jsonResponse(w, http.StatusInternalServerError, map[string]string{"error": "Failed to save Last.fm username"})
397
+
return
398
+
}
399
+
log.Printf("API: Successfully linked Last.fm username '%s' for user ID %d", reqBody.LastFMUsername, userID)
400
+
jsonResponse(w, http.StatusOK, map[string]string{"message": "Last.fm username updated successfully"})
401
+
}
402
+
}
403
+
404
+
func apiUnlinkLastfmHandler(database *db.DB) http.HandlerFunc {
405
+
return func(w http.ResponseWriter, r *http.Request) {
406
+
userID, _ := session.GetUserID(r.Context())
407
+
408
+
// TODO: add a clear username for user id fn
409
+
err := database.AddLastFMUsername(userID, "")
410
+
if err != nil {
411
+
log.Printf("apiUnlinkLastfmHandler: Error unlinking Last.fm username for user %d: %v", userID, err)
412
+
jsonResponse(w, http.StatusInternalServerError, map[string]string{"error": "Failed to unlink Last.fm username"})
413
+
return
414
+
}
415
+
log.Printf("API: Successfully unlinked Last.fm username for user ID %d", userID)
416
+
jsonResponse(w, http.StatusOK, map[string]string{"message": "Last.fm username unlinked successfully"})
417
+
}
418
+
}
+4
cmd/routes.go
+4
cmd/routes.go
···
28
28
mux.HandleFunc("/logout", app.sessionManager.HandleLogout)
29
29
mux.HandleFunc("/debug/", session.WithAuth(app.sessionManager.HandleDebug, app.sessionManager))
30
30
31
+
mux.HandleFunc("/api/v1/me", session.WithAPIAuth(apiMeHandler(app.database), app.sessionManager))
32
+
mux.HandleFunc("/api/v1/lastfm", session.WithAPIAuth(apiGetLastfmUserHandler(app.database), app.sessionManager))
33
+
mux.HandleFunc("/api/v1/lastfm/set", session.WithAPIAuth(apiLinkLastfmHandler(app.database), app.sessionManager))
34
+
mux.HandleFunc("/api/v1/lastfm/unset", session.WithAPIAuth(apiUnlinkLastfmHandler(app.database), app.sessionManager))
31
35
mux.HandleFunc("/api/v1/current-track", session.WithAPIAuth(apiCurrentTrack(app.spotifyService), app.sessionManager)) // Spotify Current
32
36
mux.HandleFunc("/api/v1/history", session.WithAPIAuth(apiTrackHistory(app.spotifyService), app.sessionManager)) // Spotify History
33
37
mux.HandleFunc("/api/v1/musicbrainz/search", apiMusicBrainzSearch(app.mbService)) // MusicBrainz (public?)
+4
-4
service/apikey/apikey.go
+4
-4
service/apikey/apikey.go
···
26
26
}
27
27
28
28
// jsonResponse is a helper to send JSON responses
29
-
func jsonResponse(w http.ResponseWriter, statusCode int, data interface{}) {
29
+
func jsonResponse(w http.ResponseWriter, statusCode int, data any) {
30
30
w.Header().Set("Content-Type", "application/json")
31
31
w.WriteHeader(statusCode)
32
32
if data != nil {
···
67
67
// Ensure keys are safe for listing (e.g., no raw key string)
68
68
// GetUserApiKeys should return a slice of db_apikey.ApiKey or similar struct
69
69
// that includes ID, Name, KeyPrefix, CreatedAt, ExpiresAt.
70
-
jsonResponse(w, http.StatusOK, map[string]interface{}{"api_keys": keys})
70
+
jsonResponse(w, http.StatusOK, map[string]any{"api_keys": keys})
71
71
72
72
case http.MethodPost:
73
73
var reqBody struct {
···
135
135
if keyName == "" {
136
136
keyName = fmt.Sprintf("API Key - %s", time.Now().Format(time.RFC3339))
137
137
}
138
-
validityDays := 30 // Default for HTML form creation
138
+
validityDays := 1024
139
139
140
140
// Uses the existing CreateAPIKey, which likely doesn't return the raw key.
141
141
// The HTML flow currently redirects and shows the key ID.
···
171
171
return
172
172
}
173
173
// AJAX client expects JSON
174
-
jsonResponse(w, http.StatusOK, map[string]interface{}{"success": true})
174
+
jsonResponse(w, http.StatusOK, map[string]any{"success": true})
175
175
return
176
176
}
177
177