mirror of
https://github.com/acaloiaro/garbagespeak.com
synced 2026-07-21 18:29:08 +00:00
Support editing garbage
This commit is contained in:
parent
8fb9646d2c
commit
add714d21f
7 changed files with 185 additions and 14 deletions
|
|
@ -105,7 +105,7 @@ enableInlineShortcodes = true
|
||||||
[[languages.en.menu.main]]
|
[[languages.en.menu.main]]
|
||||||
identifier = "submit"
|
identifier = "submit"
|
||||||
name = "Submit"
|
name = "Submit"
|
||||||
url = "/posts/new"
|
url = "/garbage/new"
|
||||||
|
|
||||||
[module]
|
[module]
|
||||||
# In case you would like to make changes to the theme and keep it locally in you repository,
|
# In case you would like to make changes to the theme and keep it locally in you repository,
|
||||||
|
|
|
||||||
46
partials/garbage/edit.html
Normal file
46
partials/garbage/edit.html
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<h2>Edit Post</h2>
|
||||||
|
<form hx-put="{{ .ApiBaseUrl }}/garbage/{{ .Garbage.ID }}">
|
||||||
|
<label for="title">A brief summary of the garbage</label>
|
||||||
|
<input
|
||||||
|
id="title"
|
||||||
|
autofocus
|
||||||
|
rquired
|
||||||
|
type="text"
|
||||||
|
name="title"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="Provide an explanation, title, or some context"
|
||||||
|
value="{{ .Garbage.Title }}"/>
|
||||||
|
|
||||||
|
<label for="garbage">Garbage Speak</label>
|
||||||
|
<textarea id="garbage"
|
||||||
|
required
|
||||||
|
minlength="10"
|
||||||
|
rows="3"
|
||||||
|
autocorrect="off"
|
||||||
|
wrap="soft"
|
||||||
|
name="garbage"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="This may be any garbage speak seen in the wild. Refer to the FAQ for what constitues garbage
|
||||||
|
speak.">{{.Garbage.Content}}</textarea>
|
||||||
|
|
||||||
|
<label for="url">URL where seen (optional)</label>
|
||||||
|
<input
|
||||||
|
id="url"
|
||||||
|
optional
|
||||||
|
type="text"
|
||||||
|
name="url"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="A public URL where this garbage was seen"
|
||||||
|
value="{{ .Garbage.Url }}"/>
|
||||||
|
|
||||||
|
<label for="tags">Tags (optional)</label>
|
||||||
|
<select id="tags" name="tags" multiple optional>
|
||||||
|
{{ range $tag := .AvailableTags }}
|
||||||
|
<option {{ if index $.SelectedTags $tag}} selected{{end}}>{{ $tag }}</option>
|
||||||
|
{{ end }}
|
||||||
|
</select>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<button>Update</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
<div class="posts">
|
<div class="posts">
|
||||||
|
{{ $apiBaseURL := .ApiBaseUrl }}
|
||||||
{{range .Posts}}
|
{{range .Posts}}
|
||||||
<article class="post on-list">
|
<article class="post on-list">
|
||||||
<h1 class="post-title">{{ .Title }}</h1>
|
<h1 class="post-title"><a href={{ .Url }}>{{ .Title }}</a></h1>
|
||||||
<div class="post-meta">
|
<div class="post-meta">
|
||||||
{{- with .Username -}}
|
{{- with .Username -}}
|
||||||
<span>Submitter: <span class="post-author">{{ . }}</span></span>
|
<span>Submitter: {{ . }}</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{ if .Metadata.tags }}
|
{{ if .Metadata.tags }}
|
||||||
<span class="">
|
<span>
|
||||||
{{ range .Metadata.tags }}
|
{{ range .Metadata.tags }}
|
||||||
{{- . -}},
|
{{- . -}},
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
@ -20,6 +20,13 @@
|
||||||
{{- .Format "2006-01-02" -}}
|
{{- .Format "2006-01-02" -}}
|
||||||
</time>
|
</time>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{ if $.LoggedIn }}
|
||||||
|
<a href="#"
|
||||||
|
hx-get="{{ $apiBaseURL }}/garbage/{{ .ID }}/edit"
|
||||||
|
hx-target="#content"
|
||||||
|
hx-swap="outerHTML">Edit</a>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
130
server.go
130
server.go
|
|
@ -173,6 +173,8 @@ func main() {
|
||||||
})
|
})
|
||||||
r.Route("/garbage", func(r chi.Router) {
|
r.Route("/garbage", func(r chi.Router) {
|
||||||
r.Post("/new", createGarbageHandler)
|
r.Post("/new", createGarbageHandler)
|
||||||
|
r.Get("/{garbage_id}/edit", editGarbageHandler)
|
||||||
|
r.Put("/{garbage_id}", editGarbageUpdateHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Printf("Starting API server on port 1314\n")
|
fmt.Printf("Starting API server on port 1314\n")
|
||||||
|
|
@ -181,6 +183,113 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func editGarbageUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
garbageID := chi.URLParam(r, "garbage_id")
|
||||||
|
userID := sessions.GetString(r.Context(), "userID")
|
||||||
|
|
||||||
|
if userID == "" {
|
||||||
|
ise(errors.New("not logged in"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
ise(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
url := r.PostForm.Get("url")
|
||||||
|
title := r.PostForm.Get("title")
|
||||||
|
garbage := r.PostForm.Get("garbage")
|
||||||
|
// TODO this is an arbitrary length that will likely need to change
|
||||||
|
if len(garbage) == 10 {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata := map[string]any{}
|
||||||
|
tags := r.Form["tags"]
|
||||||
|
if len(tags) > 0 {
|
||||||
|
metadata["tags"] = tags
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := db.Exec(ctx,
|
||||||
|
"UPDATE garbages SET (title, content, url, metadata) = ($1, $2, $3, $4) WHERE id = $5",
|
||||||
|
title,
|
||||||
|
garbage,
|
||||||
|
url,
|
||||||
|
metadata,
|
||||||
|
garbageID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("HERE")
|
||||||
|
//var buff = bytes.NewBufferString("")
|
||||||
|
//tmpl := template.Must(template.ParseFiles("partials/users/created.html"))
|
||||||
|
//err = tmpl.Execute(buff, map[string]any{"Email": email})
|
||||||
|
//if err != nil {
|
||||||
|
//ise(err, w)
|
||||||
|
//return
|
||||||
|
//}
|
||||||
|
|
||||||
|
w.Header().Add("hx-location", baseURL())
|
||||||
|
}
|
||||||
|
|
||||||
|
func editGarbageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
garbageID := chi.URLParam(r, "garbage_id")
|
||||||
|
userID := sessions.GetString(r.Context(), "userID")
|
||||||
|
if userID == "" {
|
||||||
|
return // TODO render an error
|
||||||
|
}
|
||||||
|
|
||||||
|
garbage := Garbage{}
|
||||||
|
ctx := context.Background()
|
||||||
|
err := pgxscan.Get(
|
||||||
|
ctx,
|
||||||
|
db,
|
||||||
|
&garbage,
|
||||||
|
`SELECT id, title, content, metadata, url FROM garbages WHERE id = $1`, garbageID)
|
||||||
|
if err != nil {
|
||||||
|
ise(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
availableTags := []string{
|
||||||
|
"Nouned verb",
|
||||||
|
"Verbed noun",
|
||||||
|
"Nouned adjective",
|
||||||
|
"Novel garbage",
|
||||||
|
}
|
||||||
|
selectedTags := map[string]bool{}
|
||||||
|
if tags, ok := garbage.Metadata["tags"].([]interface{}); ok {
|
||||||
|
for _, tag := range tags {
|
||||||
|
selectedTags[tag.(string)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmplVars := map[string]any{
|
||||||
|
"ApiBaseUrl": apiURL(),
|
||||||
|
"Garbage": garbage,
|
||||||
|
"SelectedTags": selectedTags,
|
||||||
|
"AvailableTags": availableTags,
|
||||||
|
}
|
||||||
|
tmpl := template.Must(template.ParseFiles("partials/garbage/edit.html"))
|
||||||
|
|
||||||
|
var buff = bytes.NewBufferString("")
|
||||||
|
err = tmpl.Execute(buff, tmplVars)
|
||||||
|
if err != nil {
|
||||||
|
ise(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "text/html")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(buff.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
// newUserValidationHandler checks whether a username is available during account creation
|
// newUserValidationHandler checks whether a username is available during account creation
|
||||||
func newUserValidationHandler(w http.ResponseWriter, r *http.Request) {
|
func newUserValidationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
tmplVars := map[string]any{"ApiBaseUrl": apiURL()}
|
tmplVars := map[string]any{"ApiBaseUrl": apiURL()}
|
||||||
|
|
@ -292,7 +401,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// logoutHandler handles users logout requests
|
// logoutHandler handles users logout requests
|
||||||
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sessions.Clear(r.Context())
|
sessions.Destroy(r.Context())
|
||||||
http.Redirect(w, r, baseURL(), http.StatusFound)
|
http.Redirect(w, r, baseURL(), http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,7 +410,6 @@ func navUserItems(w http.ResponseWriter, r *http.Request) {
|
||||||
userID := sessions.GetString(r.Context(), "userID")
|
userID := sessions.GetString(r.Context(), "userID")
|
||||||
var tmpl *template.Template
|
var tmpl *template.Template
|
||||||
|
|
||||||
log.Println("user id:", userID)
|
|
||||||
if userID == "" {
|
if userID == "" {
|
||||||
tmpl = template.Must(template.ParseFiles("partials/nav/non_user_nav_items.html"))
|
tmpl = template.Must(template.ParseFiles("partials/nav/non_user_nav_items.html"))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -371,7 +479,6 @@ func emailVerification(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createGarbageHandler(w http.ResponseWriter, r *http.Request) {
|
func createGarbageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
userID := sessions.GetString(r.Context(), "userID")
|
userID := sessions.GetString(r.Context(), "userID")
|
||||||
if userID == "" {
|
if userID == "" {
|
||||||
ise(errors.New("not logged in"), w)
|
ise(errors.New("not logged in"), w)
|
||||||
|
|
@ -392,9 +499,11 @@ func createGarbageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
url := r.PostForm.Get("url")
|
url := r.PostForm.Get("url")
|
||||||
|
|
||||||
|
metadata := map[string]any{}
|
||||||
tags := r.Form["tags"]
|
tags := r.Form["tags"]
|
||||||
metadata := map[string]any{
|
if len(tags) > 0 {
|
||||||
"tags": tags,
|
metadata["tags"] = tags
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
@ -526,7 +635,11 @@ func garbageBin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var buff = bytes.NewBufferString("")
|
var buff = bytes.NewBufferString("")
|
||||||
tmpl := template.Must(template.ParseFiles("partials/posts.html"))
|
tmpl := template.Must(template.ParseFiles("partials/posts.html"))
|
||||||
err = tmpl.Execute(buff, map[string]any{"Posts": posts})
|
err = tmpl.Execute(buff, map[string]any{
|
||||||
|
"Posts": posts,
|
||||||
|
"ApiBaseUrl": apiURL(),
|
||||||
|
"LoggedIn": isLoggedIn(r),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ise(err, w)
|
ise(err, w)
|
||||||
return
|
return
|
||||||
|
|
@ -683,3 +796,8 @@ func ise(err error, w http.ResponseWriter) {
|
||||||
fmt.Fprintf(w, "error: %v", err)
|
fmt.Fprintf(w, "error: %v", err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLoggedIn(r *http.Request) bool {
|
||||||
|
var _, err = r.Cookie("session_id")
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,11 @@
|
||||||
&-meta {
|
&-meta {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
color: transparentize($accent, .3);
|
color: transparentize($accent, .6);
|
||||||
|
|
||||||
& > *:not(:first-child) {
|
& > *:not(:first-child) {
|
||||||
&::before {
|
&::before {
|
||||||
content: "::";
|
content: "|";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
{{ partial "header.html" . }}
|
{{ partial "header.html" . }}
|
||||||
|
|
||||||
<div class="content">
|
<div id="content" class="content">
|
||||||
{{ block "main" . }}
|
{{ block "main" . }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue