mirror of
https://github.com/acaloiaro/garbagespeak.com
synced 2026-07-21 10:12:19 +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]]
|
||||
identifier = "submit"
|
||||
name = "Submit"
|
||||
url = "/posts/new"
|
||||
url = "/garbage/new"
|
||||
|
||||
[module]
|
||||
# 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">
|
||||
{{ $apiBaseURL := .ApiBaseUrl }}
|
||||
{{range .Posts}}
|
||||
<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">
|
||||
{{- with .Username -}}
|
||||
<span>Submitter: <span class="post-author">{{ . }}</span></span>
|
||||
<span>Submitter: {{ . }}</span>
|
||||
{{- end -}}
|
||||
|
||||
{{ if .Metadata.tags }}
|
||||
<span class="">
|
||||
<span>
|
||||
{{ range .Metadata.tags }}
|
||||
{{- . -}},
|
||||
{{ end }}
|
||||
|
|
@ -20,6 +20,13 @@
|
|||
{{- .Format "2006-01-02" -}}
|
||||
</time>
|
||||
{{- end -}}
|
||||
|
||||
{{ if $.LoggedIn }}
|
||||
<a href="#"
|
||||
hx-get="{{ $apiBaseURL }}/garbage/{{ .ID }}/edit"
|
||||
hx-target="#content"
|
||||
hx-swap="outerHTML">Edit</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
|||
130
server.go
130
server.go
|
|
@ -173,6 +173,8 @@ func main() {
|
|||
})
|
||||
r.Route("/garbage", func(r chi.Router) {
|
||||
r.Post("/new", createGarbageHandler)
|
||||
r.Get("/{garbage_id}/edit", editGarbageHandler)
|
||||
r.Put("/{garbage_id}", editGarbageUpdateHandler)
|
||||
})
|
||||
|
||||
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
|
||||
func newUserValidationHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tmplVars := map[string]any{"ApiBaseUrl": apiURL()}
|
||||
|
|
@ -292,7 +401,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// logoutHandler handles users logout requests
|
||||
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sessions.Clear(r.Context())
|
||||
sessions.Destroy(r.Context())
|
||||
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")
|
||||
var tmpl *template.Template
|
||||
|
||||
log.Println("user id:", userID)
|
||||
if userID == "" {
|
||||
tmpl = template.Must(template.ParseFiles("partials/nav/non_user_nav_items.html"))
|
||||
} else {
|
||||
|
|
@ -371,7 +479,6 @@ func emailVerification(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func createGarbageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
userID := sessions.GetString(r.Context(), "userID")
|
||||
if userID == "" {
|
||||
ise(errors.New("not logged in"), w)
|
||||
|
|
@ -392,9 +499,11 @@ func createGarbageHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
url := r.PostForm.Get("url")
|
||||
|
||||
metadata := map[string]any{}
|
||||
tags := r.Form["tags"]
|
||||
metadata := map[string]any{
|
||||
"tags": tags,
|
||||
if len(tags) > 0 {
|
||||
metadata["tags"] = tags
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
|
@ -526,7 +635,11 @@ func garbageBin(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var buff = bytes.NewBufferString("")
|
||||
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 {
|
||||
ise(err, w)
|
||||
return
|
||||
|
|
@ -683,3 +796,8 @@ func ise(err error, w http.ResponseWriter) {
|
|||
fmt.Fprintf(w, "error: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func isLoggedIn(r *http.Request) bool {
|
||||
var _, err = r.Cookie("session_id")
|
||||
return err == nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@
|
|||
&-meta {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 10px;
|
||||
color: transparentize($accent, .3);
|
||||
color: transparentize($accent, .6);
|
||||
|
||||
& > *:not(:first-child) {
|
||||
&::before {
|
||||
content: "::";
|
||||
content: "|";
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
{{ partial "header.html" . }}
|
||||
|
||||
<div class="content">
|
||||
<div id="content" class="content">
|
||||
{{ block "main" . }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue