Add HTML forms for actions
This commit is contained in:
parent
280c68d77a
commit
4821887b07
21
README.md
21
README.md
|
@ -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:
|
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!)
|
* `shortUrl`: The short base URL (without trailing slash!)
|
||||||
* `defaultUrl`: The default URL to which should be redirected when no slug is specified
|
* `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.
|
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
|
- Create a new short link: `/s`
|
||||||
|
- `url`: URL to shorten
|
||||||
To update a short link, call "`shortUrl` + `/d?slug=` + slug to update + `&new=` + new long URL"
|
- (optional) `slug`: the preferred slug
|
||||||
|
- Update a short link: `/u`
|
||||||
## Delete a short link
|
- `slug`: slug to update
|
||||||
|
- `new`: new long URL
|
||||||
To delete a short link, call "`shortUrl` + `/d?slug=` + slug to delete".
|
- Delete a short link: `/d`
|
||||||
|
- `slug`: slug to delete
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
87
main.go
87
main.go
|
@ -6,6 +6,7 @@ import (
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/rubenv/sql-migrate"
|
"github.com/rubenv/sql-migrate"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -50,9 +51,12 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/s", ShortenHandler)
|
r.HandleFunc("/s", ShortenFormHandler).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/u", UpdateHandler)
|
r.HandleFunc("/s", ShortenHandler).Methods(http.MethodPost)
|
||||||
r.HandleFunc("/d", DeleteHandler)
|
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("/{slug}", ShortenedUrlHandler)
|
||||||
r.HandleFunc("/", CatchAllHandler)
|
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) {
|
func ShortenHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_ = r.ParseForm()
|
||||||
|
|
||||||
if !checkPassword(w, r) {
|
if !checkPassword(w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -85,13 +150,13 @@ func ShortenHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
_, _ = w.Write([]byte(viper.GetString("shortUrl") + "/" + slug))
|
_, _ = w.Write([]byte(viper.GetString("shortUrl") + "/" + slug))
|
||||||
}
|
}
|
||||||
|
|
||||||
requestUrl := r.URL.Query().Get("url")
|
requestUrl := r.FormValue("url")
|
||||||
if requestUrl == "" {
|
if requestUrl == "" {
|
||||||
http.Error(w, "url parameter not set", http.StatusBadRequest)
|
http.Error(w, "url parameter not set", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
slug := r.URL.Query().Get("slug")
|
slug := r.FormValue("slug")
|
||||||
manualSlug := false
|
manualSlug := false
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
_ = db.QueryRow("SELECT slug FROM redirect WHERE url = ?", requestUrl).Scan(&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) {
|
func UpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_ = r.ParseForm()
|
||||||
|
|
||||||
if !checkPassword(w, r) {
|
if !checkPassword(w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
slug := r.URL.Query().Get("slug")
|
slug := r.FormValue("slug")
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
http.Error(w, "Specify the slug to update", http.StatusBadRequest)
|
http.Error(w, "Specify the slug to update", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newUrl := r.URL.Query().Get("new")
|
newUrl := r.FormValue("new")
|
||||||
if newUrl == "" {
|
if newUrl == "" {
|
||||||
http.Error(w, "Specify the new URL", http.StatusBadRequest)
|
http.Error(w, "Specify the new URL", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -164,11 +231,13 @@ func UpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteHandler(w http.ResponseWriter, r *http.Request) {
|
func DeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_ = r.ParseForm()
|
||||||
|
|
||||||
if !checkPassword(w, r) {
|
if !checkPassword(w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
slug := r.URL.Query().Get("slug")
|
slug := r.FormValue("slug")
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
http.Error(w, "Specify the slug to delete", http.StatusBadRequest)
|
http.Error(w, "Specify the slug to delete", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -190,7 +259,7 @@ func DeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPassword(w http.ResponseWriter, r *http.Request) bool {
|
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
|
return true
|
||||||
}
|
}
|
||||||
_, pass, ok := r.BasicAuth()
|
_, pass, ok := r.BasicAuth()
|
||||||
|
|
Loading…
Reference in New Issue