1
Fork 0

Add HTML forms for actions

This commit is contained in:
Jan-Lukas Else 2020-04-01 19:31:49 +02:00
parent 280c68d77a
commit 4821887b07
2 changed files with 89 additions and 19 deletions

View File

@ -8,7 +8,7 @@ Configuration can be done with a simple `config.{json|yaml|toml}` file in the wo
These are the required config values:
* `password`: Password to create or delete short links
* `password`: Password to create, update or delete short links
* `shortUrl`: The short base URL (without trailing slash!)
* `defaultUrl`: The default URL to which should be redirected when no slug is specified
@ -22,17 +22,18 @@ See the `example-config.yaml` file for an example configuration.
The preferred authentication method is Basic Authentication. If you try to create, modify or delete a short link, in the browser a popup will appear asking for username and password. Enter just the password you configured. Alternatively you can append a URL query parameter `password` with your configured password.
## Create a new short link
## Usage
To create a new short link, call "`shortUrl` + `/s?url=` + URL to shorten". If you want, you can append `&slug=` with the preferred slug.
You can either create, update or delete short links using a browser by entering the short URL and the path for the method. Or you can make a HTTP `POST` request with the parameters.
## Update a short link
To update a short link, call "`shortUrl` + `/d?slug=` + slug to update + `&new=` + new long URL"
## Delete a short link
To delete a short link, call "`shortUrl` + `/d?slug=` + slug to delete".
- Create a new short link: `/s`
- `url`: URL to shorten
- (optional) `slug`: the preferred slug
- Update a short link: `/u`
- `slug`: slug to update
- `new`: new long URL
- Delete a short link: `/d`
- `slug`: slug to delete
## License

87
main.go
View File

@ -6,6 +6,7 @@ import (
_ "github.com/mattn/go-sqlite3"
"github.com/rubenv/sql-migrate"
"github.com/spf13/viper"
"html/template"
"log"
"math/rand"
"net/http"
@ -50,9 +51,12 @@ func main() {
}()
r := mux.NewRouter()
r.HandleFunc("/s", ShortenHandler)
r.HandleFunc("/u", UpdateHandler)
r.HandleFunc("/d", DeleteHandler)
r.HandleFunc("/s", ShortenFormHandler).Methods(http.MethodGet)
r.HandleFunc("/s", ShortenHandler).Methods(http.MethodPost)
r.HandleFunc("/u", UpdateFormHandler).Methods(http.MethodGet)
r.HandleFunc("/u", UpdateHandler).Methods(http.MethodPost)
r.HandleFunc("/d", DeleteFormHandler).Methods(http.MethodGet)
r.HandleFunc("/d", DeleteHandler).Methods(http.MethodPost)
r.HandleFunc("/{slug}", ShortenedUrlHandler)
r.HandleFunc("/", CatchAllHandler)
@ -76,7 +80,68 @@ func MigrateDatabase() {
}
}
func ShortenFormHandler(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if !checkPassword(w, r) {
return
}
err := generateForm(w, "Shorten URL", "s", []string{"url", "slug"})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func UpdateFormHandler(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if !checkPassword(w, r) {
return
}
err := generateForm(w, "Update short link", "u", []string{"slug", "new"})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func DeleteFormHandler(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if !checkPassword(w, r) {
return
}
err := generateForm(w, "Delete short link", "d", []string{"slug"})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func generateForm(w http.ResponseWriter, title string, url string, fields []string) error {
tmpl, err := template.New("Form").Parse("<!doctype html><html lang=en><title>{{.Title}}</title><h1>{{.Title}}</h1><form action={{.Url}} method=post>{{range .Fields}}<input type=text name={{.}} placeholder={{.}} /><br><br>{{end}}<input type=submit value={{.Title}}></form></html>")
if err != nil {
return err
}
err = tmpl.Execute(w, &struct {
Title string
Url string
Fields []string
}{
Title: title,
Url: url,
Fields: fields,
})
if err != nil {
return err
}
return nil
}
func ShortenHandler(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if !checkPassword(w, r) {
return
}
@ -85,13 +150,13 @@ func ShortenHandler(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(viper.GetString("shortUrl") + "/" + slug))
}
requestUrl := r.URL.Query().Get("url")
requestUrl := r.FormValue("url")
if requestUrl == "" {
http.Error(w, "url parameter not set", http.StatusBadRequest)
return
}
slug := r.URL.Query().Get("slug")
slug := r.FormValue("slug")
manualSlug := false
if slug == "" {
_ = db.QueryRow("SELECT slug FROM redirect WHERE url = ?", requestUrl).Scan(&slug)
@ -132,17 +197,19 @@ func ShortenHandler(w http.ResponseWriter, r *http.Request) {
}
func UpdateHandler(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if !checkPassword(w, r) {
return
}
slug := r.URL.Query().Get("slug")
slug := r.FormValue("slug")
if slug == "" {
http.Error(w, "Specify the slug to update", http.StatusBadRequest)
return
}
newUrl := r.URL.Query().Get("new")
newUrl := r.FormValue("new")
if newUrl == "" {
http.Error(w, "Specify the new URL", http.StatusBadRequest)
return
@ -164,11 +231,13 @@ func UpdateHandler(w http.ResponseWriter, r *http.Request) {
}
func DeleteHandler(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if !checkPassword(w, r) {
return
}
slug := r.URL.Query().Get("slug")
slug := r.FormValue("slug")
if slug == "" {
http.Error(w, "Specify the slug to delete", http.StatusBadRequest)
return
@ -190,7 +259,7 @@ func DeleteHandler(w http.ResponseWriter, r *http.Request) {
}
func checkPassword(w http.ResponseWriter, r *http.Request) bool {
if r.URL.Query().Get("password") == viper.GetString("password") {
if r.FormValue("password") == viper.GetString("password") {
return true
}
_, pass, ok := r.BasicAuth()