diff --git a/assets/style.css b/assets/style.css index 9b51a95..844c811 100644 --- a/assets/style.css +++ b/assets/style.css @@ -15,8 +15,11 @@ section { row-gap: 1em; } -.status-username { +a { font-weight: bold; +} + +.status-username { margin-bottom: .5em; } @@ -28,6 +31,26 @@ section { margin-bottom: 1em; } +dt { + font-weight: bold; +} + +dd { + margin-bottom: 1em; +} + +.profile-picture { + float: right; +} + +nav { + margin-bottom: 1em; +} + +h1, h2 { + margin-top: 0; +} + @media (min-width: 650px) { .cols { grid-template-columns: repeat(2, 1fr); diff --git a/model/user.go b/model/user.go index c649e2e..cc671fc 100644 --- a/model/user.go +++ b/model/user.go @@ -13,6 +13,8 @@ type User struct { Hash []byte Homepage string About string + Style string + Picture string CreatedAt time.Time } diff --git a/storage/migration.go b/storage/migration.go index e89fd82..a04a0c3 100644 --- a/storage/migration.go +++ b/storage/migration.go @@ -7,7 +7,7 @@ import ( "strconv" ) -const schemaVersion = 3 +const schemaVersion = 6 func Migrate(db *sql.DB) { var currentVersion int diff --git a/storage/sql.go b/storage/sql.go index 65dbcad..e771881 100644 --- a/storage/sql.go +++ b/storage/sql.go @@ -32,4 +32,10 @@ create table statuses add column homepage varchar(500) not null DEFAULT '', add column about varchar(500) not null DEFAULT ''; `, + "schema_version_4": `alter table users +alter column about TYPE TEXT;`, + "schema_version_5": `alter table users + add column style TEXT not null DEFAULT '';`, + "schema_version_6": `alter table users + add column picture varchar(500) not null DEFAULT '';`, } diff --git a/storage/sql/schema_version_4.sql b/storage/sql/schema_version_4.sql new file mode 100644 index 0000000..dff65a9 --- /dev/null +++ b/storage/sql/schema_version_4.sql @@ -0,0 +1,2 @@ +alter table users +alter column about TYPE TEXT; \ No newline at end of file diff --git a/storage/sql/schema_version_5.sql b/storage/sql/schema_version_5.sql new file mode 100644 index 0000000..04faed7 --- /dev/null +++ b/storage/sql/schema_version_5.sql @@ -0,0 +1,2 @@ +alter table users + add column style TEXT not null DEFAULT ''; \ No newline at end of file diff --git a/storage/sql/schema_version_6.sql b/storage/sql/schema_version_6.sql new file mode 100644 index 0000000..589a347 --- /dev/null +++ b/storage/sql/schema_version_6.sql @@ -0,0 +1,2 @@ +alter table users + add column picture varchar(500) not null DEFAULT ''; \ No newline at end of file diff --git a/storage/status.go b/storage/status.go index 81ee7e7..63fd90a 100644 --- a/storage/status.go +++ b/storage/status.go @@ -70,27 +70,27 @@ func (s *Storage) StatusById(id int64) (model.Status, error) { return status, err } -func (s *Storage) StatusByUsername(user string, perPage int, page int64) ([]model.Status, error) { +func (s *Storage) StatusByUsername(user string, perPage int, page int64) ([]model.Status, bool, error) { rows, err := s.db.Query(statusQueryBuilder{ where: `author = $1`, limit: strconv.Itoa(perPage + 1), offset: `$2`, }.build(), user, page*int64(perPage)) if err != nil { - return nil, err + return nil, false, err } var statuses []model.Status for rows.Next() { post, err := s.populateStatus(rows) if err != nil { - return statuses, err + return nil, false, err } statuses = append(statuses, post) } if len(statuses) > perPage { - return statuses[0:perPage], err + return statuses[0:perPage], true, err } - return statuses, err + return statuses, false, err } func (s *Storage) Statuses(page int64, perPage int) ([]model.Status, bool, error) { diff --git a/storage/user.go b/storage/user.go index 0aaaf1b..9f2524b 100644 --- a/storage/user.go +++ b/storage/user.go @@ -4,10 +4,10 @@ import ( "status/model" ) -const queryFindName = `SELECT name, hash, created_at, homepage, about FROM users WHERE name=lower($1);` +const queryFindName = `SELECT name, hash, created_at, homepage, about, style, picture 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, &user.Homepage, &user.About) + err = s.db.QueryRow(q, params...).Scan(&user.Name, &user.Hash, &user.CreatedAt, &user.Homepage, &user.About, &user.Style, &user.Picture) return } @@ -77,11 +77,11 @@ func (s *Storage) DeleteUser(username string) error { 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;`) +func (s *Storage) UpdateSettings(username, homepage, about, style, picture string) error { + stmt, err := s.db.Prepare(`UPDATE users SET homepage = $1, about = $2, style = $3, picture = $4 WHERE name = $5;`) if err != nil { return err } - _, err = stmt.Exec(homepage, about, username) + _, err = stmt.Exec(homepage, about, style, picture, username) return err } diff --git a/web/handler/common.go b/web/handler/common.go index 03274f4..364ccd0 100644 --- a/web/handler/common.go +++ b/web/handler/common.go @@ -16,7 +16,13 @@ var TplCommonMap = map[string]string{
-

status ☕

+
{{ template "content" . }} @@ -32,7 +38,7 @@ var TplCommonMap = map[string]string{ `, "status": `{{ define "status" }}
-
{{ .User }}'s status, updated {{ .TimeAgo }}
+
{{ .User }}, {{ .TimeAgo }}

{{ .Content }}

{{ end }}`, diff --git a/web/handler/form/settings.go b/web/handler/form/settings.go index 6cd85db..9338731 100644 --- a/web/handler/form/settings.go +++ b/web/handler/form/settings.go @@ -7,11 +7,15 @@ import ( type SettingsForm struct { Homepage string About string + Style string + Picture string } func NewSettingsForm(r *http.Request) *SettingsForm { return &SettingsForm{ Homepage: r.FormValue("homepage"), About: r.FormValue("about"), + Style: r.FormValue("style"), + Picture: r.FormValue("picture"), } } diff --git a/web/handler/html.go b/web/handler/html.go index 0a06b28..304b404 100644 --- a/web/handler/html.go +++ b/web/handler/html.go @@ -84,7 +84,7 @@ Are you sure you you want to delete the following status? {{ end }}
- +

Update status with bookmarklet

@@ -154,17 +154,31 @@ Are you sure you you want to delete the following status?
- - + +
+
+ + +
+ +
+ + +
{{ end }}`, - "user": `{{ define "content" }} + "user": `{{ define "head" }} + +{{ end }} + +{{ define "content" }}
+

{{ .user }}

Homepage
@@ -178,6 +192,20 @@ Are you sure you you want to delete the following status? {{ range .statuses }} {{ template "status" . }} {{ end }} + {{ if or .showMore (ne 0 .page) }} +

+ {{ if ne 0 .page }} + {{ if eq 0 .prev_page }} + Newer statuses + {{ else }} + Newer statuses + {{ end }} + {{ end }} + {{ if .showMore }} + Older statuses + {{- end }} +

+ {{ end }}
{{ end }}`, diff --git a/web/handler/html/common/layout.html b/web/handler/html/common/layout.html index f783b06..bff5167 100644 --- a/web/handler/html/common/layout.html +++ b/web/handler/html/common/layout.html @@ -11,7 +11,13 @@
-

status ☕

+
{{ template "content" . }} diff --git a/web/handler/html/common/status.html b/web/handler/html/common/status.html index f31bbd0..1b96a13 100644 --- a/web/handler/html/common/status.html +++ b/web/handler/html/common/status.html @@ -1,6 +1,6 @@ {{ define "status" }} {{ end }} \ No newline at end of file diff --git a/web/handler/html/index.html b/web/handler/html/index.html index f30508f..cf54db4 100644 --- a/web/handler/html/index.html +++ b/web/handler/html/index.html @@ -10,7 +10,7 @@ {{ end }}
- +

Update status with bookmarklet

diff --git a/web/handler/html/settings.html b/web/handler/html/settings.html index 9ae8789..69ecc4f 100644 --- a/web/handler/html/settings.html +++ b/web/handler/html/settings.html @@ -11,10 +11,19 @@
- - + +
+
+ + +
+ +
+ + +
diff --git a/web/handler/html/user.html b/web/handler/html/user.html index bab2a1d..9ad72b7 100644 --- a/web/handler/html/user.html +++ b/web/handler/html/user.html @@ -1,6 +1,11 @@ +{{ define "head" }} + +{{ end }} + {{ define "content" }}
+

{{ .user }}

Homepage
@@ -14,6 +19,20 @@ {{ range .statuses }} {{ template "status" . }} {{ end }} + {{ if or .showMore (ne 0 .page) }} +

+ {{ if ne 0 .page }} + {{ if eq 0 .prev_page }} + Newer statuses + {{ else }} + Newer statuses + {{ end }} + {{ end }} + {{ if .showMore }} + Older statuses + {{- end }} +

+ {{ end }}
{{ end }} \ No newline at end of file diff --git a/web/handler/index_show.go b/web/handler/index_show.go index 688971e..cac232a 100644 --- a/web/handler/index_show.go +++ b/web/handler/index_show.go @@ -10,12 +10,13 @@ type Update struct { } func (h *Handler) showIndexView(w http.ResponseWriter, r *http.Request) { + user, _ := h.sess.Get(r) statuses, err := h.storage.LatestStatuses() if err != nil { serverError(w, err) return } - session, err := h.sess.Store.Get(r, "ichi") + session, err := h.sess.Store.Get(r, "status") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -28,5 +29,5 @@ func (h *Handler) showIndexView(w http.ResponseWriter, r *http.Request) { h.renderLayout(w, "index", map[string]interface{}{ "statuses": statuses, "flash": flash, - }, "") + }, user) } diff --git a/web/handler/settings_show.go b/web/handler/settings_show.go index 5c69480..f034b95 100644 --- a/web/handler/settings_show.go +++ b/web/handler/settings_show.go @@ -13,7 +13,7 @@ func (h *Handler) showSettingsView(w http.ResponseWriter, r *http.Request) { unauthorized(w) return } - session, err := h.sess.Store.Get(r, "ichi") + session, err := h.sess.Store.Get(r, "status") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -27,5 +27,7 @@ func (h *Handler) showSettingsView(w http.ResponseWriter, r *http.Request) { "flash": flash, "About": user.About, "Homepage": user.Homepage, + "Style": user.Style, + "Picture": user.Picture, }, username) } diff --git a/web/handler/settings-update.go b/web/handler/settings_update.go similarity index 77% rename from web/handler/settings-update.go rename to web/handler/settings_update.go index bd7a9a5..c6bcc97 100644 --- a/web/handler/settings-update.go +++ b/web/handler/settings_update.go @@ -13,11 +13,11 @@ func (h *Handler) updateSettings(w http.ResponseWriter, r *http.Request) { return } f := form.NewSettingsForm(r) - if err := h.storage.UpdateSettings(user, f.Homepage, f.About); err != nil { + if err := h.storage.UpdateSettings(user, f.Homepage, f.About, f.Style, f.Picture); err != nil { serverError(w, err) return } - session, err := h.sess.Store.Get(r, "ichi") + session, err := h.sess.Store.Get(r, "status") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/web/handler/status_edit.go b/web/handler/status_edit.go index 518d6f6..6520508 100644 --- a/web/handler/status_edit.go +++ b/web/handler/status_edit.go @@ -33,7 +33,7 @@ func (h *Handler) showEditStatusView(w http.ResponseWriter, r *http.Request) { unauthorized(w) return } - session, err := h.sess.Store.Get(r, "ichi") + session, err := h.sess.Store.Get(r, "status") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/web/handler/status_save.go b/web/handler/status_save.go index 1f4b13d..5a0b884 100644 --- a/web/handler/status_save.go +++ b/web/handler/status_save.go @@ -29,7 +29,7 @@ func (h *Handler) saveStatus(w http.ResponseWriter, r *http.Request) { return } if r.URL.Query().Get("silent") != "1" { - session, err := h.sess.Store.Get(r, "ichi") + session, err := h.sess.Store.Get(r, "status") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/web/handler/status_update.go b/web/handler/status_update.go index 72a498e..cfcc566 100644 --- a/web/handler/status_update.go +++ b/web/handler/status_update.go @@ -35,7 +35,7 @@ func (h *Handler) updateStatus(w http.ResponseWriter, r *http.Request) { serverError(w, err) return } - session, err := h.sess.Store.Get(r, "ichi") + session, err := h.sess.Store.Get(r, "status") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/web/handler/user_show.go b/web/handler/user_show.go index 7fcda58..a99b2e9 100644 --- a/web/handler/user_show.go +++ b/web/handler/user_show.go @@ -9,30 +9,43 @@ import ( "golang.org/x/image/font" "golang.org/x/image/font/gofont/goregular" "golang.org/x/image/math/fixed" + "html/template" "image" "image/color" "image/draw" + "strconv" + //"image/png" "net/http" ) func (h *Handler) showUserView(w http.ResponseWriter, r *http.Request) { + var page int64 = 0 + if val, ok := r.URL.Query()["page"]; ok && len(val[0]) == 1 { + page, _ = strconv.ParseInt(val[0], 10, 64) + } username := mux.Vars(r)["user"] user, err := h.storage.UserByName(username) if err != nil { notFound(w) return } - statuses, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 20, 0) + statuses, showMore, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 20, page) if err != nil { serverError(w, err) return } h.renderLayout(w, "user", map[string]interface{}{ - "user": username, - "statuses": statuses, - "homepage": user.Homepage, - "about": user.About, + "user": username, + "statuses": statuses, + "homepage": user.Homepage, + "about": template.HTML(user.About), + "picture": user.Picture, + "style": template.CSS(user.Style), + "showMore": showMore, + "page": page, + "next_page": page + 1, + "prev_page": page - 1, }, username) } @@ -48,7 +61,7 @@ func (h *Handler) showUserStatusView(w http.ResponseWriter, r *http.Request) { notFound(w) return } - statuses, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0) + statuses, _, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0) if err != nil { serverError(w, err) return @@ -113,7 +126,7 @@ func (h *Handler) showUserStatusImageView(w http.ResponseWriter, r *http.Request notFound(w) return } - statuses, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0) + statuses, _, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0) if err != nil { serverError(w, err) return @@ -137,11 +150,11 @@ func (h *Handler) showUserStatusImageView(w http.ResponseWriter, r *http.Request } width := 350 - dc := gg.NewContext(width, 80) + dc := gg.NewContext(width, 84) dc.SetHexColor(background) dc.Clear() dc.SetHexColor(foreground) - dc.DrawStringWrapped(text, 19, 16, 0, 0, float64(width-(2*16)), 1.5, gg.AlignLeft) + dc.DrawStringWrapped(text, 8, 4, 0, 0, float64(width-(2*16)), 1.5, gg.AlignLeft) dc.EncodePNG(w) //dc.SavePNG("out.png")