diff --git a/handler.go b/handler.go index 4ae9585..cc69c17 100644 --- a/handler.go +++ b/handler.go @@ -26,10 +26,11 @@ var templates = template.Must(template.ParseFS(templateFiles, "templates/*.tpl") type page struct { Short string + URLs []*links.URL } -func (srv *server) servePage(w http.ResponseWriter, p page) { - err := templates.ExecuteTemplate(w, "index.tpl", p) +func (srv *server) servePage(w http.ResponseWriter, p page, tpl string) { + err := templates.ExecuteTemplate(w, tpl, p) if err != nil { log.Printf("error executing template: %s", err) http.Error(w, fmt.Sprintf("template execution failed: %s", err.Error()), @@ -51,6 +52,12 @@ func (srv *server) postURL(w http.ResponseWriter, r *http.Request) { return } + url, err = links.CleanString(url) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + ctx := context.Background() short, err := links.StoreURL(ctx, srv.db, url) if err != nil { @@ -58,7 +65,7 @@ func (srv *server) postURL(w http.ResponseWriter, r *http.Request) { return } - srv.servePage(w, page{Short: short}) + srv.servePage(w, page{Short: short}, "index.tpl") } func (srv *server) redirect(w http.ResponseWriter, r *http.Request) { @@ -72,6 +79,20 @@ func (srv *server) redirect(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, u, http.StatusFound) } +func (srv *server) listAll(w http.ResponseWriter, r *http.Request) { + allPosts, err := links.FetchAll(context.Background(), srv.db) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + p := page{ + URLs: allPosts, + } + + srv.servePage(w, p, "list.tpl") +} + func (srv *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet && links.ValidShortCode.MatchString(r.URL.Path) { srv.redirect(w, r) @@ -94,5 +115,10 @@ func (srv *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - srv.servePage(w, page{}) + if r.URL.Path == "/list" { + srv.listAll(w, r) + return + } + + srv.servePage(w, page{}, "index.tpl") } diff --git a/links/url.go b/links/url.go index 47197dc..f40ec45 100644 --- a/links/url.go +++ b/links/url.go @@ -22,6 +22,10 @@ type URL struct { CreatedAt time.Time } +func (u *URL) Timestamp() string { + return u.CreatedAt.Format("2006-01-02 15:04") +} + func (u *URL) Store(ctx context.Context, db *pgxpool.Pool) error { stmt := psql.Insert("urls"). Columns("id", "url", "nurl", "short", "created_at"). @@ -56,6 +60,29 @@ func NormalizeString(s string) (string, error) { return u.String(), nil } +// Clean should scrub out junk from the URL. +func Clean(u *url.URL) *url.URL { + norm := &url.URL{ + Scheme: u.Scheme, + Host: u.Host, + Path: u.Path, + RawPath: u.RawPath, + Fragment: u.Fragment, + RawFragment: u.RawFragment, + } + return norm +} + +func CleanString(s string) (string, error) { + u, err := url.Parse(s) + if err != nil { + return "", err + } + + u = Clean(u) + return u.String(), nil +} + func New(u *url.URL) *URL { link := &URL{ ID: uuid.NewString(), @@ -144,3 +171,35 @@ func RetrieveURL(ctx context.Context, db *pgxpool.Pool, short string) (string, e return url, nil } + +func FetchAll(ctx context.Context, db *pgxpool.Pool) ([]*URL, error) { + stmt := psql.Select("*").From("urls").OrderBy("created_at") + query, args, err := stmt.ToSql() + if err != nil { + return nil, err + } + + rows, err := db.Query(ctx, query, args...) + if err != nil { + return nil, err + } + + var urls []*URL + for rows.Next() { + u := &URL{} + err = rows.Scan( + &u.ID, + &u.URL, + &u.NURL, + &u.Short, + &u.CreatedAt, + ) + if err != nil { + return nil, err + } + + urls = append(urls, u) + } + + return urls, nil +} diff --git a/templates/list.tpl b/templates/list.tpl new file mode 100644 index 0000000..dd103f4 --- /dev/null +++ b/templates/list.tpl @@ -0,0 +1,25 @@ + + + + kls + + + + + + + + + + +

KLS

+

Home

+ + +