Fix routes and flash

This commit is contained in:
m15o 2021-11-28 08:40:11 +01:00
parent d480796fd3
commit ecf4203f39
19 changed files with 294 additions and 154 deletions

View file

@ -7,7 +7,13 @@ body {
section {
padding: 1em;
background-color: peachpuff;
background-color: lightblue;
}
.flash {
background-color: lightgreen;
padding: 0.5em 1em;
color: darkgreen;
}
.cols {

View file

@ -3,13 +3,18 @@
package handler
var TplCommonMap = map[string]string{
"flash": `{{ define "flash" }}
{{ if . }}
<p class="flash">{{ . }}</p>
{{ end }}
{{ end }}`,
"layout": `{{ define "layout" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>status </title>
<title>status.cafe</title>
<meta name="description" content="your friends' updates">
<link rel="stylesheet" href="/assets/style.css"/>
{{ template "head" . }}
@ -17,7 +22,7 @@ var TplCommonMap = map[string]string{
<body>
<header>
<nav>
<a href="/">status </a>
<a href="/">status.cafe</a>
{{ if .logged }}
<a href="/settings">settings</a> <a href="/users/{{ .logged }}">{{ .logged }}</a> (<a href="/logout">logout</a>)
{{ else }}

View file

@ -73,12 +73,13 @@ func New(cfg *config.Config, sess *session.Session, data *storage.Storage) (http
router.HandleFunc("/settings", h.showSettingsView).Methods(http.MethodGet)
router.HandleFunc("/settings-update", h.updateSettings).Methods(http.MethodPost)
router.HandleFunc("/status-new", h.showNewStatusView).Methods(http.MethodGet)
router.HandleFunc("/status-save", h.saveStatus).Methods(http.MethodPost)
router.HandleFunc("/status-remove", h.handleRemoveStatus)
router.HandleFunc("/statuses/{id}/edit", h.showEditStatusView).Methods(http.MethodGet)
router.HandleFunc("/statuses/{id}/update", h.updateStatus).Methods(http.MethodPost)
router.HandleFunc("/add", h.showNewStatusView).Methods(http.MethodGet)
router.HandleFunc("/add", h.saveStatus).Methods(http.MethodPost)
router.HandleFunc("/remove", h.handleRemoveStatus)
router.HandleFunc("/edit", h.showEditStatusView).Methods(http.MethodGet)
router.HandleFunc("/edit", h.updateStatus).Methods(http.MethodPost)
router.HandleFunc("/manage", h.showManageView).Methods(http.MethodGet)
router.HandleFunc("/users/{user}", h.showUserView).Methods(http.MethodGet)
router.HandleFunc("/users/{user}/status.json", h.showUserStatusView).Methods(http.MethodGet)
router.HandleFunc("/users/{user}/status.png", h.showUserStatusImageView).Methods(http.MethodGet)

View file

@ -4,12 +4,14 @@ package handler
var TplMap = map[string]string{
"confirm_remove_status": `{{ define "content" }}
Are you sure you you want to delete the following status?
<p>{{ .status.Content }}</p>
<form action="/status-remove?id={{ .status.Id }}" method="post">
<input type="hidden" name="id"/>
<input type="submit" value="Submit">
</form>
<section>
Are you sure you you want to delete the following status?
<p>{{ .status.Content }}</p>
<form action="/remove?id={{ .status.Id }}" method="post">
<input type="hidden" name="id"/>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}`,
"create_status": `<!DOCTYPE html>
<html lang="en">
@ -18,19 +20,24 @@ Are you sure you you want to delete the following status?
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>status cafe</title>
<meta name="description" content="your friends' updates">
<style>
body {
background-color: lightblue;
font-family: Verdana;
}
</style>
</head>
<body>
<main>
<h1>New status</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/status-save?silent=1" method="post" name="update-status">
<form action="/add?silent=1" method="post" name="update-status">
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus></textarea>
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 120px" autofocus></textarea>
</div>
<br>
<input type="submit" value="Submit">
@ -40,7 +47,7 @@ Are you sure you you want to delete the following status?
<script>
document.forms["update-status"].onsubmit = function (event) {
event.preventDefault();
fetch("/status-save?silent=1", {
fetch("/add?silent=1", {
method: "POST",
body: new FormData(document.forms["update-status"])
})
@ -56,21 +63,21 @@ Are you sure you you want to delete the following status?
</body>
</html>`,
"edit_status": `{{ define "content" }}
<h1>Edit status</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/statuses/{{ .status.Id }}/update" method="post">
<div class="field">
<section>
<h1>Edit status</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ template "flash" .flash }}
<form action="/edit?id={{ .status.Id }}" method="post">
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus>{{ .status.Content }}</textarea>
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus>{{ .status.Content }}</textarea>
</div>
</div>
</div>
<input type="submit" value="Submit">
</form>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}`,
"index": `{{ define "content" }}
<div class="cols">
@ -79,16 +86,14 @@ Are you sure you you want to delete the following status?
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/status-save" method="post">
{{ template "flash" .flash }}
<form action="/add" method="post">
<div class="field">
<textarea name="content" maxlength="140" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 100px;" autofocus></textarea>
</div>
<input type="submit" value="Submit">
<h3>Update status with bookmarklet</h3>
<p>Drag to your bookmarks to update from anywhere: <a href="javascript:void(open('https://status.cafe/status-new','status.cafe','resizable,scrollbars,width=360,height=200'))">Set status</a></p>
<p>Drag to your bookmarks to update from anywhere: <a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=360,height=200'))">status.cafe</a></p>
<h3>Display status on your homepage</h3>
<p>todo</p>
</form>
@ -98,53 +103,88 @@ Are you sure you you want to delete the following status?
{{ range .statuses }}
<article class="status">
{{ template "status" . }}
{{ if eq $.logged .User }}
<nav><a href="/status-remove?id={{ .Id }}">Delete</a> <a href="/statuses/{{ .Id }}/edit">Edit</a></nav>
{{ end }}
</article>
{{ end }}
</section>
</div>
{{ end }}`,
"login": `{{ define "content" }}
<h1>Login</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/check-login" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
<section>
<h1>Login</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/check-login" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}`,
"manage": `{{ define "content" }}
<section>
<h2>Manage statuses</h2>
{{ template "flash" .flash }}
{{ range .statuses }}
<article class="status">
{{ template "status" . }}
{{ if eq $.logged .User }}
<nav><a href="/edit?id={{ .Id }}">Edit</a> <a href="/remove?id={{ .Id }}">Delete</a></nav>
{{ end }}
</article>
{{ end }}
{{ if or .showMore (ne 0 .page) }}
<p>
{{ if ne 0 .page }}
{{ if eq 0 .prev_page }}
<a href="manage">Newer statuses</a>
{{ else }}
<a href="manage?page={{ .prev_page }}">Newer statuses</a>
{{ end }}
{{ end }}
{{ if .showMore }}
<a href="manage?page={{ .next_page }}">Older statuses</a>
{{- end }}
</p>
{{ end }}
</section>
{{ end }}`,
"register": `{{ define "content" }}
<h1>Register</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/register" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<div class="field">
<label for="password-confirm">Confirm password</label>
<input type="password" id="password-confirm" name="password-confirm" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
<section>
<h1>Register</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/register" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<div class="field">
<label for="password-confirm">Confirm password</label>
<input type="password" id="password-confirm" name="password-confirm" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}`,
"remove_success": `{{ define "content" }}
<section>
{{ template "flash" .flash }}
<a href="/">Back home</a>
</section>
{{ end }}`,
"settings": `{{ define "content" }}
<section>
@ -152,6 +192,7 @@ Are you sure you you want to delete the following status?
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<p><a href="/manage">Manage statuses</a></p>
<form action="/settings-update" method="post">
<div class="field">
<label for="homepage">homepage</label>
@ -197,9 +238,6 @@ Are you sure you you want to delete the following status?
{{ range .statuses }}
<article class="status">
{{ template "status" . }}
{{ if eq $.logged .User }}
<nav><a href="/status-remove?id={{ .Id }}">Delete</a> <a href="/statuses/{{ .Id }}/edit">Edit</a></nav>
{{ end }}
</article>
{{ end }}
{{ if or .showMore (ne 0 .page) }}

View file

@ -0,0 +1,5 @@
{{ define "flash" }}
{{ if . }}
<p class="flash">{{ . }}</p>
{{ end }}
{{ end }}

View file

@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>status</title>
<title>status.cafe</title>
<meta name="description" content="your friends' updates">
<link rel="stylesheet" href="/assets/style.css"/>
{{ template "head" . }}
@ -12,7 +12,7 @@
<body>
<header>
<nav>
<a href="/">status</a>
<a href="/">status.cafe</a>
{{ if .logged }}
<a href="/settings">settings</a> <a href="/users/{{ .logged }}">{{ .logged }}</a> (<a href="/logout">logout</a>)
{{ else }}

View file

@ -1,8 +1,10 @@
{{ define "content" }}
Are you sure you you want to delete the following status?
<p>{{ .status.Content }}</p>
<form action="/status-remove?id={{ .status.Id }}" method="post">
<input type="hidden" name="id"/>
<input type="submit" value="Submit">
</form>
<section>
Are you sure you you want to delete the following status?
<p>{{ .status.Content }}</p>
<form action="/remove?id={{ .status.Id }}" method="post">
<input type="hidden" name="id"/>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}

View file

@ -5,19 +5,24 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>status cafe</title>
<meta name="description" content="your friends' updates">
<style>
body {
background-color: lightblue;
font-family: Verdana;
}
</style>
</head>
<body>
<main>
<h1>New status</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/status-save?silent=1" method="post" name="update-status">
<form action="/add?silent=1" method="post" name="update-status">
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus></textarea>
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 120px" autofocus></textarea>
</div>
<br>
<input type="submit" value="Submit">
@ -27,7 +32,7 @@
<script>
document.forms["update-status"].onsubmit = function (event) {
event.preventDefault();
fetch("/status-save?silent=1", {
fetch("/add?silent=1", {
method: "POST",
body: new FormData(document.forms["update-status"])
})

View file

@ -1,17 +1,17 @@
{{ define "content" }}
<h1>Edit status</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/statuses/{{ .status.Id }}/update" method="post">
<div class="field">
<section>
<h1>Edit status</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ template "flash" .flash }}
<form action="/edit?id={{ .status.Id }}" method="post">
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus>{{ .status.Content }}</textarea>
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus>{{ .status.Content }}</textarea>
</div>
</div>
</div>
<input type="submit" value="Submit">
</form>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}

View file

@ -5,16 +5,14 @@
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/status-save" method="post">
{{ template "flash" .flash }}
<form action="/add" method="post">
<div class="field">
<textarea name="content" maxlength="140" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 100px;" autofocus></textarea>
</div>
<input type="submit" value="Submit">
<h3>Update status with bookmarklet</h3>
<p>Drag to your bookmarks to update from anywhere: <a href="javascript:void(open('https://status.cafe/status-new','status.cafe','resizable,scrollbars,width=360,height=200'))">Set status</a></p>
<p>Drag to your bookmarks to update from anywhere: <a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=360,height=200'))">status.cafe</a></p>
<h3>Display status on your homepage</h3>
<p>todo</p>
</form>
@ -24,9 +22,6 @@
{{ range .statuses }}
<article class="status">
{{ template "status" . }}
{{ if eq $.logged .User }}
<nav><a href="/status-remove?id={{ .Id }}">Delete</a> <a href="/statuses/{{ .Id }}/edit">Edit</a></nav>
{{ end }}
</article>
{{ end }}
</section>

View file

@ -1,18 +1,20 @@
{{ define "content" }}
<h1>Login</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/check-login" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
<section>
<h1>Login</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/check-login" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}

View file

@ -0,0 +1,28 @@
{{ define "content" }}
<section>
<h2>Manage statuses</h2>
{{ template "flash" .flash }}
{{ range .statuses }}
<article class="status">
{{ template "status" . }}
{{ if eq $.logged .User }}
<nav><a href="/edit?id={{ .Id }}">Edit</a> <a href="/remove?id={{ .Id }}">Delete</a></nav>
{{ end }}
</article>
{{ end }}
{{ if or .showMore (ne 0 .page) }}
<p>
{{ if ne 0 .page }}
{{ if eq 0 .prev_page }}
<a href="manage">Newer statuses</a>
{{ else }}
<a href="manage?page={{ .prev_page }}">Newer statuses</a>
{{ end }}
{{ end }}
{{ if .showMore }}
<a href="manage?page={{ .next_page }}">Older statuses</a>
{{- end }}
</p>
{{ end }}
</section>
{{ end }}

View file

@ -1,22 +1,24 @@
{{ define "content" }}
<h1>Register</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/register" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<div class="field">
<label for="password-confirm">Confirm password</label>
<input type="password" id="password-confirm" name="password-confirm" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
<section>
<h1>Register</h1>
{{ if .form.Error }}
<p>{{ .form.Error }}</p>
{{ end }}
<form action="/register" method="post" class="auth-form">
<div class="field">
<label for="name">Username</label>
<input type="text" id="name" name="name" autocomplete="off" required autofocus/>
</div>
<div class="field">
<label for="password">Password</label>
<input type="password" id="password" name="password" required/>
</div>
<div class="field">
<label for="password-confirm">Confirm password</label>
<input type="password" id="password-confirm" name="password-confirm" required/>
</div>
<br>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}

View file

@ -4,6 +4,7 @@
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<p><a href="/manage">Manage statuses</a></p>
<form action="/settings-update" method="post">
<div class="field">
<label for="homepage">homepage</label>

View file

@ -19,9 +19,6 @@
{{ range .statuses }}
<article class="status">
{{ template "status" . }}
{{ if eq $.logged .User }}
<nav><a href="/status-remove?id={{ .Id }}">Delete</a> <a href="/statuses/{{ .Id }}/edit">Edit</a></nav>
{{ end }}
</article>
{{ end }}
{{ if or .showMore (ne 0 .page) }}

View file

@ -24,7 +24,12 @@ func (h *Handler) showEditStatusView(w http.ResponseWriter, r *http.Request) {
unauthorized(w)
return
}
status, err := h.storage.StatusById(RouteInt64Param(r, "id"))
id, err := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)
if err != nil {
serverError(w, err)
return
}
status, err := h.storage.StatusById(id)
if err != nil {
serverError(w, err)
return

View file

@ -36,6 +36,13 @@ func (h *Handler) handleRemoveStatus(w http.ResponseWriter, r *http.Request) {
serverError(w, err)
return
}
http.Redirect(w, r, "/", http.StatusFound)
session, err := h.sess.Store.Get(r, "status")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session.AddFlash("Status successfully removed!")
err = session.Save(r, w)
http.Redirect(w, r, "/manage", http.StatusFound)
}
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"status/web/handler/form"
"strconv"
)
func (h *Handler) updateStatus(w http.ResponseWriter, r *http.Request) {
@ -12,7 +13,12 @@ func (h *Handler) updateStatus(w http.ResponseWriter, r *http.Request) {
unauthorized(w)
return
}
status, err := h.storage.StatusById(RouteInt64Param(r, "id"))
id, err := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)
if err != nil {
serverError(w, err)
return
}
status, err := h.storage.StatusById(id)
if err != nil {
serverError(w, err)
return
@ -42,5 +48,5 @@ func (h *Handler) updateStatus(w http.ResponseWriter, r *http.Request) {
}
session.AddFlash("Status edited!")
err = session.Save(r, w)
http.Redirect(w, r, fmt.Sprintf("/statuses/%d/edit", status.Id), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/edit?id=%d", status.Id), http.StatusFound)
}

View file

@ -19,6 +19,41 @@ import (
"net/http"
)
func (h *Handler) showManageView(w http.ResponseWriter, r *http.Request) {
logged, err := h.sess.Get(r)
if err != nil {
unauthorized(w)
return
}
var page int64 = 0
if val, ok := r.URL.Query()["page"]; ok && len(val[0]) == 1 {
page, _ = strconv.ParseInt(val[0], 10, 64)
}
statuses, showMore, err := h.storage.StatusByUsername(logged, 20, page)
if err != nil {
serverError(w, err)
return
}
session, err := h.sess.Store.Get(r, "status")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
flash := ""
if flashes := session.Flashes(); len(flashes) > 0 {
flash = flashes[0].(string)
}
session.Save(r, w)
h.renderLayout(w, "manage", map[string]interface{}{
"statuses": statuses,
"showMore": showMore,
"page": page,
"flash": flash,
"next_page": page + 1,
"prev_page": page - 1,
}, logged)
}
func (h *Handler) showUserView(w http.ResponseWriter, r *http.Request) {
logged, _ := h.sess.Get(r)
var page int64 = 0