diff --git a/cmd/scanner/main.go b/cmd/scanner/main.go index 8e0798c..8f04355 100644 --- a/cmd/scanner/main.go +++ b/cmd/scanner/main.go @@ -187,6 +187,7 @@ func main() { &db.Track{}, &db.Cover{}, &db.User{}, + &db.Setting{}, ) // 🤫🤫🤫 orm.Exec(` diff --git a/cmd/server/main.go b/cmd/server/main.go index 8686f2c..b2641b7 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -87,10 +87,13 @@ func setAdminRoutes(mux *http.ServeMux) { mux.HandleFunc("/admin/home", withUserWare(cont.ServeHome)) mux.HandleFunc("/admin/change_own_password", withUserWare(cont.ServeChangeOwnPassword)) mux.HandleFunc("/admin/change_own_password_do", withUserWare(cont.ServeChangeOwnPasswordDo)) + mux.HandleFunc("/admin/link_lastfm_callback", withUserWare(cont.ServeLinkLastFMCallback)) mux.HandleFunc("/admin/change_password", withAdminWare(cont.ServeChangePassword)) mux.HandleFunc("/admin/change_password_do", withAdminWare(cont.ServeChangePasswordDo)) mux.HandleFunc("/admin/create_user", withAdminWare(cont.ServeCreateUser)) mux.HandleFunc("/admin/create_user_do", withAdminWare(cont.ServeCreateUserDo)) + mux.HandleFunc("/admin/update_lastfm_api_key", withAdminWare(cont.ServeUpdateLastFMAPIKey)) + mux.HandleFunc("/admin/update_lastfm_api_key_do", withAdminWare(cont.ServeUpdateLastFMAPIKeyDo)) } func main() { diff --git a/db/model.go b/db/model.go index 1e67aa2..9c7b4e4 100644 --- a/db/model.go +++ b/db/model.go @@ -55,3 +55,10 @@ type User struct { Password string IsAdmin bool } + +// Setting represents the settings table +type Setting struct { + CrudBase + Key string `gorm:"primary_key;auto_increment:false"` + Value string +} diff --git a/go.mod b/go.mod index 105acfb..19d2d84 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,7 @@ module github.com/sentriz/gonic require ( cloud.google.com/go v0.37.1 // indirect + github.com/davecgh/go-spew v1.1.1 github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853 // indirect github.com/dhowden/tag v0.0.0-20181104225729-a9f04c2798ca github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect diff --git a/handler/admin.go b/handler/admin.go index a553134..667114a 100644 --- a/handler/admin.go +++ b/handler/admin.go @@ -74,6 +74,15 @@ func (c *Controller) ServeChangeOwnPasswordDo(w http.ResponseWriter, r *http.Req http.Redirect(w, r, "/admin/home", 303) } +func (c *Controller) ServeLinkLastFMCallback(w http.ResponseWriter, r *http.Request) { + token := r.URL.Query().Get("token") + if token == "" { + http.Error(w, "please provide a token", 400) + return + } + _ = token +} + func (c *Controller) ServeChangePassword(w http.ResponseWriter, r *http.Request) { username := r.URL.Query().Get("user") if username == "" { @@ -148,3 +157,36 @@ func (c *Controller) ServeCreateUserDo(w http.ResponseWriter, r *http.Request) { } http.Redirect(w, r, "/admin/home", 303) } + +func (c *Controller) ServeUpdateLastFMAPIKey(w http.ResponseWriter, r *http.Request) { + var data templateData + var apiKey db.Setting + var secret db.Setting + c.DB.Where("key = ?", "lastfm_api_key").First(&apiKey) + c.DB.Where("key = ?", "lastfm_secret").First(&secret) + data.CurrentLastFMAPIKey = apiKey.Value + data.CurrentLastFMAPISecret = secret.Value + renderTemplate(w, r, "update_lastfm_api_key", &data) +} + +func (c *Controller) ServeUpdateLastFMAPIKeyDo(w http.ResponseWriter, r *http.Request) { + session := r.Context().Value("session").(*sessions.Session) + apiKey := r.FormValue("api_key") + secret := r.FormValue("secret") + err := utilities.ValidateAPIKey(apiKey, secret) + if err != nil { + session.AddFlash(err.Error()) + session.Save(r, w) + http.Redirect(w, r, r.Header.Get("Referer"), 302) + return + } + c.DB. + Where(db.Setting{Key: "lastfm_api_key"}). + Assign(db.Setting{Value: apiKey}). + FirstOrCreate(&db.Setting{}) + c.DB. + Where(db.Setting{Key: "lastfm_secret"}). + Assign(db.Setting{Value: secret}). + FirstOrCreate(&db.Setting{}) + http.Redirect(w, r, "/admin/home", 303) +} diff --git a/handler/handler.go b/handler/handler.go index c1df8e2..d34a42e 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -47,6 +47,11 @@ func init() { filepath.Join("templates", "user.tmpl"), filepath.Join("templates", "pages", "create_user.tmpl"), )) + templates["update_lastfm_api_key"] = template.Must(template.ParseFiles( + filepath.Join("templates", "layout.tmpl"), + filepath.Join("templates", "user.tmpl"), + filepath.Join("templates", "pages", "update_lastfm_api_key.tmpl"), + )) } type Controller struct { @@ -55,13 +60,16 @@ type Controller struct { } type templateData struct { - Flashes []interface{} - User *db.User - SelectedUser *db.User - AllUsers []*db.User - ArtistCount uint - AlbumCount uint - TrackCount uint + Flashes []interface{} + User *db.User + SelectedUser *db.User + AllUsers []*db.User + ArtistCount uint + AlbumCount uint + TrackCount uint + CurrentLastFMAPIKey string + CurrentLastFMAPISecret string + RequestRoot string } func getStrParam(r *http.Request, key string) string { @@ -146,6 +154,11 @@ func renderTemplate(w http.ResponseWriter, r *http.Request, if ok { data.User = user } + if r.URL.Host == "" { + data.RequestRoot = "http://localhost" + } else { + data.RequestRoot = fmt.Sprintf("%s://%s", r.URL.Scheme, r.URL.Host) + } err := templates[name].ExecuteTemplate(w, "layout", data) if err != nil { http.Error(w, fmt.Sprintf("500 when executing: %v", err), 500) diff --git a/handler/utilities/utilities.go b/handler/utilities/utilities.go index d9371f8..53697ef 100644 --- a/handler/utilities/utilities.go +++ b/handler/utilities/utilities.go @@ -18,3 +18,10 @@ func ValidatePasswords(pOne, pTwo string) error { } return nil } + +func ValidateAPIKey(apiKey, secret string) error { + if apiKey == "" || secret == "" { + return fmt.Errorf("please enter both the api key and secret") + } + return nil +} diff --git a/lastfm/lastfm.go b/lastfm/lastfm.go new file mode 100644 index 0000000..a70674c --- /dev/null +++ b/lastfm/lastfm.go @@ -0,0 +1,55 @@ +package lastfm + +import ( + "crypto/md5" + "encoding/hex" + "encoding/xml" + "fmt" + "net/http" + "net/url" + "time" +) + +var ( + baseURL = "http://ws.audioscrobbler.com/2.0/" + client = &http.Client{ + Timeout: 10 * time.Second, + } +) + +func getParamSignature(params url.Values, secret string) string { + toHash := "" + for k, v := range params { + toHash += k + toHash += v[0] + } + toHash += secret + hash := md5.Sum([]byte(toHash)) + return hex.EncodeToString(hash[:]) +} + +func GetSession(apiKey, secret, token string) (error, string) { + params := url.Values{} + // the first 3 parameters here must be in alphabetical order + params.Add("api_key", apiKey) + params.Add("method", "auth.getSession") + params.Add("token", token) + params.Add("api_sig", getParamSignature(params, secret)) + req, _ := http.NewRequest("GET", baseURL, nil) + req.URL.RawQuery = params.Encode() + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("error when making request to last.fm: %v", err), "" + } + defer resp.Body.Close() + decoder := xml.NewDecoder(resp.Body) + var lastfm LastFM + err = decoder.Decode(&lastfm) + if err != nil { + return fmt.Errorf("error when decoding last.fm response: %v", err), "" + } + if lastfm.Error != nil { + return fmt.Errorf("error when parsing last.fm response: %v", lastfm.Error.Value), "" + } + return nil, lastfm.Session.Key +} diff --git a/lastfm/models.go b/lastfm/models.go new file mode 100644 index 0000000..1890096 --- /dev/null +++ b/lastfm/models.go @@ -0,0 +1,21 @@ +package lastfm + +import "encoding/xml" + +type LastFM struct { + XMLName xml.Name `xml:"lfm"` + Status string `xml:"status,attr"` + Session *Session `xml:"session"` + Error *Error `xml:"error"` +} + +type Session struct { + Name string `xml:"name"` + Key string `xml:"key"` + Subscriber uint `xml:"subscriber"` +} + +type Error struct { + Code uint `xml:"code,attr"` + Value string `xml:",chardata"` +} diff --git a/static/stylesheets/main.css b/static/stylesheets/main.css index 3df79d1..eba0ee8 100644 --- a/static/stylesheets/main.css +++ b/static/stylesheets/main.css @@ -8,6 +8,9 @@ form { max-width: 400px; margin-left: auto; margin-right: 0; + display: flex; + flex-direction: column; + align-items: flex-end; } /* reset from awsm */ @@ -30,6 +33,10 @@ form input[type=password], form input[type=text] { margin-bottom: 0.25rem; } +form input[type=submit] { + width: 8rem; +} + #content > * { margin: 2rem 0; } @@ -81,12 +88,3 @@ form input[type=password], form input[type=text] { background-color: #fd1b1b1c; } -#login-form { - display: flex; - flex-direction: column; - align-items: flex-end; -} - -#login-form input[type=submit] { - width: 8rem; -} diff --git a/templates/pages/change_own_password.tmpl b/templates/pages/change_own_password.tmpl index e4b7f64..1392b07 100644 --- a/templates/pages/change_own_password.tmpl +++ b/templates/pages/change_own_password.tmpl @@ -3,9 +3,9 @@ {{ define "user" }}
- changing account password + changing account password
-
+ diff --git a/templates/pages/change_password.tmpl b/templates/pages/change_password.tmpl index 6169c5e..305a950 100644 --- a/templates/pages/change_password.tmpl +++ b/templates/pages/change_password.tmpl @@ -3,9 +3,9 @@ {{ define "user" }}
- changing {{ .SelectedUser.Name }}'s password + changing {{ .SelectedUser.Name }}'s password
- + diff --git a/templates/pages/create_user.tmpl b/templates/pages/create_user.tmpl index 17fd06c..018b3da 100644 --- a/templates/pages/create_user.tmpl +++ b/templates/pages/create_user.tmpl @@ -3,9 +3,9 @@ {{ define "user" }}
- create new user + create new user
- + diff --git a/templates/pages/home.tmpl b/templates/pages/home.tmpl index 61533ca..036043b 100644 --- a/templates/pages/home.tmpl +++ b/templates/pages/home.tmpl @@ -3,7 +3,7 @@ {{ define "user" }}
- stats + stats
artists: {{ printf "%7v" .ArtistCount }}
@@ -13,32 +13,32 @@
- last fm + last.fm
{{ if .User.IsAdmin }} {{/* admin panel to manage all users */}}
- users + users
{{ range $user := .AllUsers }} - {{ $user.Name }} created {{ $user.CreatedAt.Format "Jan 02, 2006" }} change password
+ {{ $user.Name }} created {{ $user.CreatedAt.Format "Jan 02, 2006" }} change password
{{ end }} -
create new
{{ else }} {{/* user panel to manage themselves */}}
- your account + your account
{{ end }}
diff --git a/templates/pages/login.tmpl b/templates/pages/login.tmpl index b53f544..d7820c8 100644 --- a/templates/pages/login.tmpl +++ b/templates/pages/login.tmpl @@ -3,9 +3,9 @@ {{ define "content" }}
- please login + please login
- + diff --git a/templates/pages/update_lastfm_api_key.tmpl b/templates/pages/update_lastfm_api_key.tmpl new file mode 100644 index 0000000..26e22c5 --- /dev/null +++ b/templates/pages/update_lastfm_api_key.tmpl @@ -0,0 +1,18 @@ +{{ define "title" }}home{{ end }} + +{{ define "user" }} +
+
+ updating last.fm api key +
+
+ current key {{ if .CurrentLastFMAPIKey }}{{ .CurrentLastFMAPIKey }}{{ else }}not set{{ end }}
+ current secret {{ if .CurrentLastFMAPISecret }}{{ .CurrentLastFMAPISecret }}{{ else }}not set{{ end }} +
+ + + + + +
+{{ end }} diff --git a/templates/user.tmpl b/templates/user.tmpl index 4d89c0d..7bcaae0 100644 --- a/templates/user.tmpl +++ b/templates/user.tmpl @@ -2,7 +2,7 @@ {{ define "content" }}
- welcome {{ .User.Name }} | home | logout + welcome {{ .User.Name }} | home | logout
{{ template "user" . }} {{ end }}