Add settings

This commit is contained in:
m15o 2021-11-25 07:37:30 +01:00
parent 8cd8720a7f
commit e3238c54ad
15 changed files with 190 additions and 25 deletions

View file

@ -33,4 +33,8 @@ section {
grid-template-columns: repeat(2, 1fr);
grid-gap: 1em;
}
}
}
.field { margin-bottom: 1rem; max-width: 500px; }
.field > label { margin-bottom: .25rem; }
.field > * { display: block; width: 100%; box-sizing: border-box; }

View file

@ -8,10 +8,12 @@ import (
)
type User struct {
Name string
Password string
Hash []byte
CreatedAt time.Time
Name string
Password string
Hash []byte
Homepage string
About string
CreatedAt time.Time
}
func (u User) Validate() error {

View file

@ -7,7 +7,7 @@ import (
"strconv"
)
const schemaVersion = 2
const schemaVersion = 3
func Migrate(db *sql.DB) {
var currentVersion int

View file

@ -27,5 +27,9 @@ create table statuses
`,
"schema_version_2": `alter table users
add column status_id int references statuses(id);
`,
"schema_version_3": `alter table users
add column homepage varchar(500) not null DEFAULT '',
add column about varchar(500) not null DEFAULT '';
`,
}

View file

@ -0,0 +1,3 @@
alter table users
add column homepage varchar(500) not null DEFAULT '',
add column about varchar(500) not null DEFAULT '';

View file

@ -4,11 +4,10 @@ import (
"status/model"
)
const queryFindName = `SELECT name, hash, created_at FROM users WHERE name=lower($1);`
const queryFindDomain = `SELECT name, hash, created_at FROM users WHERE domain=$1;`
const queryFindName = `SELECT name, hash, created_at, homepage, about FROM users WHERE name=lower($1);`
func (s *Storage) queryUser(q string, params ...interface{}) (user model.User, err error) {
err = s.db.QueryRow(q, params...).Scan(&user.Name, &user.Hash, &user.CreatedAt)
err = s.db.QueryRow(q, params...).Scan(&user.Name, &user.Hash, &user.CreatedAt, &user.Homepage, &user.About)
return
}
@ -77,3 +76,12 @@ func (s *Storage) DeleteUser(username string) error {
_, err = stmt.Exec(username)
return err
}
func (s *Storage) UpdateSettings(username, homepage, about string) error {
stmt, err := s.db.Prepare(`UPDATE users SET homepage = $1, about = $2 WHERE name = $3;`)
if err != nil {
return err
}
_, err = stmt.Exec(homepage, about, username)
return err
}

View file

@ -0,0 +1,17 @@
package form
import (
"net/http"
)
type SettingsForm struct {
Homepage string
About string
}
func NewSettingsForm(r *http.Request) *SettingsForm {
return &SettingsForm{
Homepage: r.FormValue("homepage"),
About: r.FormValue("about"),
}
}

View file

@ -70,6 +70,9 @@ func New(cfg *config.Config, sess *session.Session, data *storage.Storage) (http
router.HandleFunc("/register", h.handleRegister)
router.HandleFunc("/logout", h.logout).Methods(http.MethodGet)
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("/statuses/{id}/edit", h.showEditStatusView).Methods(http.MethodGet)

View file

@ -86,7 +86,6 @@ Are you sure you you want to delete the following status?
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 100px;" autofocus></textarea>
</div>
<br>
<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>
@ -142,12 +141,44 @@ Are you sure you you want to delete the following status?
<input type="submit" value="Submit">
</form>
{{ end }}`,
"user": `{{ define "content" }}
"settings": `{{ define "content" }}
<section>
<h2>{{ .user }}</h2>
{{ range .statuses }}
{{ template "status" . }}
<h1>Settings</h1>
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/settings-update" method="post">
<div class="field">
<label for="homepage">homepage</label>
<input type="text" name="homepage" id="homepage" value="{{ .Homepage }}" autocomplete="off"/>
</div>
<div class="field">
<label for="about">about</label>
<textarea name="about" id="about">{{ .About }}</textarea>
</div>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}`,
"user": `{{ define "content" }}
<div class="cols">
<section>
<h2>{{ .user }}</h2>
<dl>
<dt>Homepage</dt>
<dd><a href="{{ .homepage }}" target="_blank">{{ .homepage }}</a></dd>
<dt>About</dt>
<dd>{{ .about }}</dd>
</dl>
</section>
<section>
<h2>Statuses</h2>
{{ range .statuses }}
{{ template "status" . }}
{{ end }}
</section>
</div>
{{ end }}`,
}

View file

@ -12,7 +12,6 @@
<div class="field">
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 100px;" autofocus></textarea>
</div>
<br>
<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>

View file

@ -0,0 +1,21 @@
{{ define "content" }}
<section>
<h1>Settings</h1>
{{ if .flash }}
<p>{{ .flash }}</p>
{{ end }}
<form action="/settings-update" method="post">
<div class="field">
<label for="homepage">homepage</label>
<input type="text" name="homepage" id="homepage" value="{{ .Homepage }}" autocomplete="off"/>
</div>
<div class="field">
<label for="about">about</label>
<textarea name="about" id="about">{{ .About }}</textarea>
</div>
<input type="submit" value="Submit">
</form>
</section>
{{ end }}

View file

@ -1,8 +1,19 @@
{{ define "content" }}
<section>
<h2>{{ .user }}</h2>
{{ range .statuses }}
{{ template "status" . }}
{{ end }}
</section>
<div class="cols">
<section>
<h2>{{ .user }}</h2>
<dl>
<dt>Homepage</dt>
<dd><a href="{{ .homepage }}" target="_blank">{{ .homepage }}</a></dd>
<dt>About</dt>
<dd>{{ .about }}</dd>
</dl>
</section>
<section>
<h2>Statuses</h2>
{{ range .statuses }}
{{ template "status" . }}
{{ end }}
</section>
</div>
{{ end }}

View file

@ -0,0 +1,28 @@
package handler
import (
"fmt"
"net/http"
"status/web/handler/form"
)
func (h *Handler) updateSettings(w http.ResponseWriter, r *http.Request) {
user, err := h.getUser(r)
if err != nil {
unauthorized(w)
return
}
f := form.NewSettingsForm(r)
if err := h.storage.UpdateSettings(user, f.Homepage, f.About); err != nil {
serverError(w, err)
return
}
session, err := h.sess.Store.Get(r, "ichi")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session.AddFlash("Status edited!")
err = session.Save(r, w)
http.Redirect(w, r, fmt.Sprintf("/settings"), http.StatusFound)
}

View file

@ -0,0 +1,31 @@
package handler
import "net/http"
func (h *Handler) showSettingsView(w http.ResponseWriter, r *http.Request) {
username, err := h.getUser(r)
if err != nil {
unauthorized(w)
return
}
user, err := h.storage.UserByName(username)
if err != nil {
unauthorized(w)
return
}
session, err := h.sess.Store.Get(r, "ichi")
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, "settings", map[string]interface{}{
"flash": flash,
"About": user.About,
"Homepage": user.Homepage,
}, username)
}

View file

@ -17,8 +17,9 @@ import (
)
func (h *Handler) showUserView(w http.ResponseWriter, r *http.Request) {
user := mux.Vars(r)["user"]
if !h.storage.UserExists(user) {
username := mux.Vars(r)["user"]
user, err := h.storage.UserByName(username)
if err != nil {
notFound(w)
return
}
@ -28,9 +29,11 @@ func (h *Handler) showUserView(w http.ResponseWriter, r *http.Request) {
return
}
h.renderLayout(w, "user", map[string]interface{}{
"user": user,
"user": username,
"statuses": statuses,
}, "")
"homepage": user.Homepage,
"about": user.About,
}, username)
}
type statusjson struct {