clean URLs by default
This commit is contained in:
parent
8756e3deb8
commit
7285264fed
34
handler.go
34
handler.go
|
@ -26,10 +26,11 @@ var templates = template.Must(template.ParseFS(templateFiles, "templates/*.tpl")
|
||||||
|
|
||||||
type page struct {
|
type page struct {
|
||||||
Short string
|
Short string
|
||||||
|
URLs []*links.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *server) servePage(w http.ResponseWriter, p page) {
|
func (srv *server) servePage(w http.ResponseWriter, p page, tpl string) {
|
||||||
err := templates.ExecuteTemplate(w, "index.tpl", p)
|
err := templates.ExecuteTemplate(w, tpl, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error executing template: %s", err)
|
log.Printf("error executing template: %s", err)
|
||||||
http.Error(w, fmt.Sprintf("template execution failed: %s", err.Error()),
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
url, err = links.CleanString(url)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
short, err := links.StoreURL(ctx, srv.db, url)
|
short, err := links.StoreURL(ctx, srv.db, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,7 +65,7 @@ func (srv *server) postURL(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
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) {
|
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)
|
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) {
|
func (srv *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method == http.MethodGet && links.ValidShortCode.MatchString(r.URL.Path) {
|
if r.Method == http.MethodGet && links.ValidShortCode.MatchString(r.URL.Path) {
|
||||||
srv.redirect(w, r)
|
srv.redirect(w, r)
|
||||||
|
@ -94,5 +115,10 @@ func (srv *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.servePage(w, page{})
|
if r.URL.Path == "/list" {
|
||||||
|
srv.listAll(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
srv.servePage(w, page{}, "index.tpl")
|
||||||
}
|
}
|
||||||
|
|
59
links/url.go
59
links/url.go
|
@ -22,6 +22,10 @@ type URL struct {
|
||||||
CreatedAt time.Time
|
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 {
|
func (u *URL) Store(ctx context.Context, db *pgxpool.Pool) error {
|
||||||
stmt := psql.Insert("urls").
|
stmt := psql.Insert("urls").
|
||||||
Columns("id", "url", "nurl", "short", "created_at").
|
Columns("id", "url", "nurl", "short", "created_at").
|
||||||
|
@ -56,6 +60,29 @@ func NormalizeString(s string) (string, error) {
|
||||||
return u.String(), nil
|
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 {
|
func New(u *url.URL) *URL {
|
||||||
link := &URL{
|
link := &URL{
|
||||||
ID: uuid.NewString(),
|
ID: uuid.NewString(),
|
||||||
|
@ -144,3 +171,35 @@ func RetrieveURL(ctx context.Context, db *pgxpool.Pool, short string) (string, e
|
||||||
|
|
||||||
return url, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>kls</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<meta property="og:title" content="kls" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="https://kls.ai6ua.net/" />
|
||||||
|
<style>
|
||||||
|
* { font-size: large; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h2>KLS</h2>
|
||||||
|
<p><a href="/">Home</a></p>
|
||||||
|
<ul>
|
||||||
|
{{range .URLs}}
|
||||||
|
<li>({{.Timestamp}}) <a href="/{{.Short}}">{{.Short}}</a> → <a href="{{.URL}}">{{.NURL}}</a></li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue