diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go index 875968c..e33839e 100644 --- a/cmd/web/handlers.go +++ b/cmd/web/handlers.go @@ -1,8 +1,8 @@ package main import ( - "fmt" - "errors" + "errors" + "fmt" "net/http" "text/template" @@ -52,6 +52,17 @@ func (app *application) webmasterCreate(w http.ResponseWriter, r *http.Request) } func (app *application) siteEntryView(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/sites/view" { + entries, err := app.siteEntries.Latest() + if err != nil { + app.serverError(w, err) + return + } + for _, entry := range entries { + fmt.Fprintf(w, "%+v\n", entry) + } + return + } id := models.SiteId(r.URL.Query().Get("id")) siteEntry, err := app.siteEntries.Get(id) @@ -71,8 +82,37 @@ func (app *application) siteEntryCreate(w http.ResponseWriter, r *http.Request) } func (app *application) nextSiteEntry(w http.ResponseWriter, r *http.Request) { + ref := app.cleanUrl(r.Referer()) + refSite, err := app.siteEntries.GetByUrl(ref) + if err != nil { + app.serverError(w, err) + return + } + nextSite, err := app.siteEntries.Get(refSite.Next) + if err != nil { + app.serverError(w, err) + app.infoLog.Printf("%+v", nextSite) + return + } + // TODO ping next site to see if it is up + w.Header().Set("Location", nextSite.Url) + w.WriteHeader(http.StatusFound) } func (app *application) prevSiteEntry(w http.ResponseWriter, r *http.Request) { + ref := app.cleanUrl(r.Referer()) + refSite, err := app.siteEntries.GetByUrl(ref) + if err != nil { + app.serverError(w, err) + return + } + prevSite, err := app.siteEntries.Get(refSite.Prev) + if err != nil { + app.serverError(w, err) + return + } + // TODO ping next site to see if it is up + w.Header().Set("Location", prevSite.Url) + w.WriteHeader(http.StatusFound) } diff --git a/cmd/web/helpers.go b/cmd/web/helpers.go index 4f76b13..505665c 100644 --- a/cmd/web/helpers.go +++ b/cmd/web/helpers.go @@ -3,7 +3,9 @@ package main import ( "fmt" "net/http" + "path" "runtime/debug" + "strings" ) func (app *application) serverError(w http.ResponseWriter, err error) { @@ -20,3 +22,11 @@ func (app *application) clientError(w http.ResponseWriter, status int) { func (app *application) notFound(w http.ResponseWriter) { app.clientError(w, http.StatusNotFound) } + +func (app *application) cleanUrl(url string) string { + s, _ := strings.CutPrefix(url, "http://") + s, _ = strings.CutPrefix(s, "https://") + s = path.Base(path.Clean(s)) + s = "http://" + s + return s +} diff --git a/cmd/web/routes.go b/cmd/web/routes.go index ce26a71..6eeac87 100644 --- a/cmd/web/routes.go +++ b/cmd/web/routes.go @@ -12,6 +12,8 @@ func (app *application) routes() *http.ServeMux { mux.HandleFunc("/", app.home) mux.HandleFunc("/webmasters/view", app.webmasterView) mux.HandleFunc("/sites/view", app.siteEntryView) + mux.HandleFunc("/next", app.nextSiteEntry) + mux.HandleFunc("/prev", app.prevSiteEntry) return mux } diff --git a/internal/models/siteentry.go b/internal/models/siteentry.go index d853c72..c307e13 100644 --- a/internal/models/siteentry.go +++ b/internal/models/siteentry.go @@ -40,7 +40,7 @@ func (m *SiteEntryModel) Insert(name string, url string, webmaster *Webmaster) ( // Retrieve a SiteEntry from the database by id func (m *SiteEntryModel) Get(id SiteId) (*SiteEntry, error) { - stmt := `SELECT id, name, url, webmaster, dateAdded FROM siteentries + stmt := `SELECT id, name, url, webmaster, dateAdded, next, prev FROM siteentries WHERE id = ?` row := m.DB.QueryRow(stmt, id) @@ -48,7 +48,7 @@ func (m *SiteEntryModel) Get(id SiteId) (*SiteEntry, error) { var timeStr string - err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr) + err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr, &s.Next, &s.Prev) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNoRecord @@ -57,7 +57,7 @@ func (m *SiteEntryModel) Get(id SiteId) (*SiteEntry, error) { } } // time is stored as a string in sqlite, so we need to parse it - // probably should be something taken care of in the driver + // probably is something taken care of in the driver dateAdded, err := time.Parse(time.DateTime, timeStr) if err != nil { return nil, err @@ -69,7 +69,31 @@ func (m *SiteEntryModel) Get(id SiteId) (*SiteEntry, error) { // Retrieve a SiteEntry from the database by url func (m *SiteEntryModel) GetByUrl(url string) (*SiteEntry, error) { - return nil, nil + stmt := `SELECT id, name, url, webmaster, dateAdded, next, prev FROM siteentries + WHERE url = ?` + + row := m.DB.QueryRow(stmt, url) + s := &SiteEntry{} + + + var timeStr string + err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr, &s.Next, &s.Prev) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNoRecord + } else { + return nil, err + } + } + // time is stored as a string in sqlite, so we need to parse it + // probably is something taken care of in the driver + s.DateAdded, err = time.Parse(time.DateTime, timeStr) + if err != nil { + return nil, err + } + + return s, nil + } // Update existing SiteEntry with the values of passed entry @@ -81,3 +105,39 @@ func (m *SiteEntryModel) Update(entry *SiteEntry) error { func (m *SiteEntryModel) Delete(entry *SiteEntry) error { return nil } + +// Get latest +func (m *SiteEntryModel) Latest() ([]*SiteEntry, error) { + stmt := `SELECT id, name, url, webmaster, dateAdded FROM siteentries + ORDER BY dateAdded DESC LIMIT 10` + + rows, err := m.DB.Query(stmt) + if err != nil { + return nil, err + } + + defer rows.Close() + + entries := []*SiteEntry{} + var timeStr string + + for rows.Next() { + s := &SiteEntry{} + err = rows.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr) + if err != nil { + return nil, err + } + s.DateAdded, err = time.Parse(time.DateTime, timeStr) + if err != nil { + return nil, err + } + + entries = append(entries, s) + } + + if err = rows.Err(); err != nil { + return nil, err + } + + return entries, nil +}