package main import ( "github.com/lamperi/e4bot/spotify" "html/template" "log" "net/http" "strings" ) var ( cachedTemplates = template.Must(template.ParseFiles("web/index.html")) spotifyClient *spotify.SpotifyClient ) func indexHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.Error(w, "Not Found", http.StatusNotFound) return } data := struct { Username string Songs []*struct { RoundID int RoundName string Title string Artist string URL string Sync bool } }{ "", make([]*struct { RoundID int RoundName string Title string Artist string URL string Sync bool }, 0), } session, err := getSession(r) if session != nil { query := ` SELECT r.id, r.section, e.artist, e.title, e.spotify_url, e.synced FROM public.round r LEFT JOIN public.entry e ON r.id = e.round_id LEFT JOIN public."user" u ON u.id = e.user_id AND lower(u.username) = lower($1) ORDER BY r.start ASC` rows, err := getDb().Query(query, session.username) if err != nil { log.Println("Error while executing query", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() for i := 0; rows.Next(); i++ { row := &struct { RoundID int RoundName string Title string Artist string URL string Sync bool }{} data.Songs = append(data.Songs, row) var ( artist, title, url *string sync *bool ) err = rows.Scan(&data.Songs[i].RoundID, &data.Songs[i].RoundName, &artist, &title, &url, &sync) if err != nil { log.Println("Error while scanning cursor", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } if artist != nil { row.Artist = *artist } if title != nil { row.Title = *title } if url != nil { row.URL = *url } if sync != nil { row.Sync = *sync } } data.Username = session.username } var templates = cachedTemplates if true { templates = template.Must(template.ParseFiles("web/index.html")) } err = templates.ExecuteTemplate(w, "index.html", data) if err != nil { log.Println("Error while rendering template", err) http.Error(w, err.Error(), http.StatusInternalServerError) } } func getTrackID(url string) string { const externalURLPrefix = "https://open.spotify.com/track/" const trackURIPrefix = "spotify:track:" if strings.HasPrefix(url, externalURLPrefix) { return strings.Split(url, externalURLPrefix)[1] } else if strings.HasPrefix(url, trackURIPrefix) { return strings.Split(url, trackURIPrefix)[1] } return url } func updateHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/update" { http.Error(w, "Forbidden", http.StatusForbidden) return } session, err := getSession(r) if session == nil { http.Redirect(w, r, "/", http.StatusTemporaryRedirect) return } err = r.ParseForm() if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } round := r.Form.Get("round") artist := r.Form.Get("artist") title := r.Form.Get("title") url := r.Form.Get("url") if artist == "" && title == "" && url != "" { log.Println("Resolving Spotify URL") trackID := getTrackID(url) err := spotifyClient.Authenticate() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } track, err := spotifyClient.GetTrack(trackID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } log.Printf("Found Track with name %v and artists %v\n", track.Name, track.Artists) for index, trackArtist := range track.Artists { if index == 0 { artist = trackArtist.Name } else if index == 1 { artist = artist + " feat. " + trackArtist.Name } else { artist = artist + ", " + trackArtist.Name } } title = track.Name url = track.ExternalUrls.Spotify } query := ` INSERT INTO public.entry SELECT id, $2, $3, $4, $5, false FROM public."user" u WHERE lower(u.username) = lower($1) ON CONFLICT (user_id, round_id) DO UPDATE SET artist = EXCLUDED.artist, title = EXCLUDED.title, spotify_url = EXCLUDED.spotify_url, synced = EXCLUDED.synced` res, err := getDb().Exec(query, session.username, round, artist, title, url) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } affected, err := res.RowsAffected() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if affected != 1 { http.Error(w, err.Error(), http.StatusInternalServerError) return } log.Printf("Updated song for round %s, artist: %s, title: %s, URL: %s", round, artist, title, url) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } func loginHandler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } username := r.Form.Get("username") password := r.Form.Get("password") remember := r.Form.Get("remember") longer := remember == "remember-me" cookie, err := tryLogin(username, password, longer) if err != nil { log.Println("Error while trying to login", err.Error()) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) return } http.SetCookie(w, &cookie) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } func webStart(listenAddr string, spot *spotify.SpotifyClient) { spotifyClient = spot mux := http.NewServeMux() fs := http.FileServer(http.Dir("web")) mux.Handle("/css/", fs) mux.Handle("/fonts/", fs) mux.Handle("/js/", fs) mux.Handle("/favicon.ico", fs) mux.HandleFunc("/", indexHandler) mux.HandleFunc("/update", updateHandler) mux.HandleFunc("/login", loginHandler) http.ListenAndServe(listenAddr, mux) }