From 92da069ce4b704f28dd97457d1b025b31c5cd43e Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 14 Feb 2020 13:55:24 -0500 Subject: [PATCH 01/17] Move admin dashboard sections into subpages This moves app config to a "Settings" page and the application monitor to a "Monitor" page. It also reworks the admin navigation bar a bit and adds some instance stats on the dashboard. Ref T694 --- admin.go | 51 ++++++++- less/admin.less | 8 +- routes.go | 2 + templates/user/admin.tmpl | 146 ++----------------------- templates/user/admin/app-settings.tmpl | 85 ++++++++++++++ templates/user/admin/monitor.tmpl | 105 ++++++++++++++++++ templates/user/include/header.tmpl | 4 +- 7 files changed, 259 insertions(+), 142 deletions(-) create mode 100644 templates/user/admin/app-settings.tmpl create mode 100644 templates/user/admin/monitor.tmpl diff --git a/admin.go b/admin.go index 5f7d244..33445ac 100644 --- a/admin.go +++ b/admin.go @@ -1,5 +1,5 @@ /* - * Copyright © 2018-2019 A Bunch Tell LLC. + * Copyright © 2018-2020 A Bunch Tell LLC. * * This file is part of WriteFreely. * @@ -100,6 +100,33 @@ func (c instanceContent) UpdatedFriendly() string { } func handleViewAdminDash(app *App, u *User, w http.ResponseWriter, r *http.Request) error { + p := struct { + *UserPage + Message string + + UsersCount, CollectionsCount, PostsCount int64 + }{ + UserPage: NewUserPage(app, r, u, "Admin", nil), + Message: r.FormValue("m"), + } + + // Get user stats + p.UsersCount = app.db.GetAllUsersCount() + var err error + p.CollectionsCount, err = app.db.GetTotalCollections() + if err != nil { + return err + } + p.PostsCount, err = app.db.GetTotalPosts() + if err != nil { + return err + } + + showUserPage(w, "admin", p) + return nil +} + +func handleViewAdminMonitor(app *App, u *User, w http.ResponseWriter, r *http.Request) error { updateAppStats() p := struct { *UserPage @@ -116,7 +143,25 @@ func handleViewAdminDash(app *App, u *User, w http.ResponseWriter, r *http.Reque ConfigMessage: r.FormValue("cm"), } - showUserPage(w, "admin", p) + showUserPage(w, "monitor", p) + return nil +} + +func handleViewAdminSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) error { + p := struct { + *UserPage + Config config.AppCfg + + Message, ConfigMessage string + }{ + UserPage: NewUserPage(app, r, u, "Admin", nil), + Config: app.cfg.App, + + Message: r.FormValue("m"), + ConfigMessage: r.FormValue("cm"), + } + + showUserPage(w, "app-settings", p) return nil } @@ -475,7 +520,7 @@ func handleAdminUpdateConfig(apper Apper, u *User, w http.ResponseWriter, r *htt if err != nil { m = "?cm=" + err.Error() } - return impart.HTTPError{http.StatusFound, "/admin" + m + "#config"} + return impart.HTTPError{http.StatusFound, "/admin/settings" + m + "#config"} } func updateAppStats() { diff --git a/less/admin.less b/less/admin.less index 9c4a7c2..3cbf30b 100644 --- a/less/admin.less +++ b/less/admin.less @@ -13,11 +13,11 @@ nav#admin { display: block; margin: 0.5em 0; a { - color: @primary; - &:first-child { - margin-left: 0; - } + margin-left: 0; + .rounded(.25em); + border: 0; &.selected { + background: #dedede; font-weight: bold; } } diff --git a/routes.go b/routes.go index fcd00ec..e606fbc 100644 --- a/routes.go +++ b/routes.go @@ -152,6 +152,8 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { write.HandleFunc("/auth/login", handler.Web(webLogin, UserLevelNoneRequired)).Methods("POST") write.HandleFunc("/admin", handler.Admin(handleViewAdminDash)).Methods("GET") + write.HandleFunc("/admin/monitor", handler.Admin(handleViewAdminMonitor)).Methods("GET") + write.HandleFunc("/admin/settings", handler.Admin(handleViewAdminSettings)).Methods("GET") write.HandleFunc("/admin/users", handler.Admin(handleViewAdminUsers)).Methods("GET") write.HandleFunc("/admin/user/{username}", handler.Admin(handleViewAdminUser)).Methods("GET") write.HandleFunc("/admin/user/{username}/status", handler.Admin(handleAdminToggleUserStatus)).Methods("POST") diff --git a/templates/user/admin.tmpl b/templates/user/admin.tmpl index 3cb81be..1a0e6b4 100644 --- a/templates/user/admin.tmpl +++ b/templates/user/admin.tmpl @@ -35,6 +35,14 @@ form dt { p.docs { font-size: 0.86em; } +.stats { + font-size: 1.2em; + margin: 1em 0; +} +.num { + font-weight: bold; + font-size: 1.5em; +}
@@ -42,142 +50,12 @@ p.docs { {{if .Message}}

{{.Message}}

{{end}} -

On this page

- - -

Resources

- - -
- -

App Configuration

-

Read more in the configuration docs.

- - {{if .ConfigMessage}}

{{.ConfigMessage}}

{{end}} - -
-
-
-
- +
+
{{largeNumFmt .UsersCount}} {{pluralize "user" "users" .UsersCount}}
+
{{largeNumFmt .CollectionsCount}} {{pluralize "blog" "blogs" .CollectionsCount}}
+
{{largeNumFmt .PostsCount}} {{pluralize "post" "posts" .PostsCount}}
- -
- -

Application

- -
-
-
WriteFreely
-
{{.Version}}
-
Server Uptime
-
{{.SysStatus.Uptime}}
-
Current Goroutines
-
{{.SysStatus.NumGoroutine}}
-
-
Current memory usage
-
{{.SysStatus.MemAllocated}}
-
Total mem allocated
-
{{.SysStatus.MemTotal}}
-
Memory obtained
-
{{.SysStatus.MemSys}}
-
Pointer lookup times
-
{{.SysStatus.Lookups}}
-
Memory allocate times
-
{{.SysStatus.MemMallocs}}
-
Memory free times
-
{{.SysStatus.MemFrees}}
-
-
Current heap usage
-
{{.SysStatus.HeapAlloc}}
-
Heap memory obtained
-
{{.SysStatus.HeapSys}}
-
Heap memory idle
-
{{.SysStatus.HeapIdle}}
-
Heap memory in use
-
{{.SysStatus.HeapInuse}}
-
Heap memory released
-
{{.SysStatus.HeapReleased}}
-
Heap objects
-
{{.SysStatus.HeapObjects}}
-
-
Bootstrap stack usage
-
{{.SysStatus.StackInuse}}
-
Stack memory obtained
-
{{.SysStatus.StackSys}}
-
MSpan structures in use
-
{{.SysStatus.MSpanInuse}}
-
MSpan structures obtained
-
{{.SysStatus.HeapSys}}
-
MCache structures in use
-
{{.SysStatus.MCacheInuse}}
-
MCache structures obtained
-
{{.SysStatus.MCacheSys}}
-
Profiling bucket hash table obtained
-
{{.SysStatus.BuckHashSys}}
-
GC metadata obtained
-
{{.SysStatus.GCSys}}
-
Other system allocation obtained
-
{{.SysStatus.OtherSys}}
-
-
Next GC recycle
-
{{.SysStatus.NextGC}}
-
Since last GC
-
{{.SysStatus.LastGC}}
-
Total GC pause
-
{{.SysStatus.PauseTotalNs}}
-
Last GC pause
-
{{.SysStatus.PauseNs}}
-
GC times
-
{{.SysStatus.NumGC}}
-
-
+ +{{template "footer" .}} + +{{template "body-end" .}} +{{end}} diff --git a/templates/user/admin/monitor.tmpl b/templates/user/admin/monitor.tmpl new file mode 100644 index 0000000..e803dd3 --- /dev/null +++ b/templates/user/admin/monitor.tmpl @@ -0,0 +1,105 @@ +{{define "monitor"}} +{{template "header" .}} + + + +
+ {{template "admin-header" .}} + + {{if .Message}}

{{.Message}}

{{end}} + +

Application Monitor

+ +
+
+
WriteFreely
+
{{.Version}}
+
Server Uptime
+
{{.SysStatus.Uptime}}
+
Current Goroutines
+
{{.SysStatus.NumGoroutine}}
+
+
Current memory usage
+
{{.SysStatus.MemAllocated}}
+
Total mem allocated
+
{{.SysStatus.MemTotal}}
+
Memory obtained
+
{{.SysStatus.MemSys}}
+
Pointer lookup times
+
{{.SysStatus.Lookups}}
+
Memory allocate times
+
{{.SysStatus.MemMallocs}}
+
Memory free times
+
{{.SysStatus.MemFrees}}
+
+
Current heap usage
+
{{.SysStatus.HeapAlloc}}
+
Heap memory obtained
+
{{.SysStatus.HeapSys}}
+
Heap memory idle
+
{{.SysStatus.HeapIdle}}
+
Heap memory in use
+
{{.SysStatus.HeapInuse}}
+
Heap memory released
+
{{.SysStatus.HeapReleased}}
+
Heap objects
+
{{.SysStatus.HeapObjects}}
+
+
Bootstrap stack usage
+
{{.SysStatus.StackInuse}}
+
Stack memory obtained
+
{{.SysStatus.StackSys}}
+
MSpan structures in use
+
{{.SysStatus.MSpanInuse}}
+
MSpan structures obtained
+
{{.SysStatus.HeapSys}}
+
MCache structures in use
+
{{.SysStatus.MCacheInuse}}
+
MCache structures obtained
+
{{.SysStatus.MCacheSys}}
+
Profiling bucket hash table obtained
+
{{.SysStatus.BuckHashSys}}
+
GC metadata obtained
+
{{.SysStatus.GCSys}}
+
Other system allocation obtained
+
{{.SysStatus.OtherSys}}
+
+
Next GC recycle
+
{{.SysStatus.NextGC}}
+
Since last GC
+
{{.SysStatus.LastGC}}
+
Total GC pause
+
{{.SysStatus.PauseTotalNs}}
+
Last GC pause
+
{{.SysStatus.PauseNs}}
+
GC times
+
{{.SysStatus.NumGC}}
+
+
+
+ +{{template "footer" .}} + +{{template "body-end" .}} +{{end}} diff --git a/templates/user/include/header.tmpl b/templates/user/include/header.tmpl index 0704854..f7c06ef 100644 --- a/templates/user/include/header.tmpl +++ b/templates/user/include/header.tmpl @@ -97,12 +97,14 @@ {{define "admin-header"}}

Admin

-
{{end}} From b58464addbe0be591c257f244e8bc5f53f15d89d Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 14 Feb 2020 14:08:53 -0500 Subject: [PATCH 02/17] Optionally hide Monitor page in Admin nav This adds a new config option that signifies the admin doesn't need to see deeply technical things, like application resource usage. In the [app] section, set forest = true to enable this. Ref T694 --- config/config.go | 1 + templates/user/include/header.tmpl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/config/config.go b/config/config.go index 2616e9e..2313732 100644 --- a/config/config.go +++ b/config/config.go @@ -93,6 +93,7 @@ type ( // Site functionality Chorus bool `ini:"chorus"` + Forest bool `ini:"forest"` // The admin cares about the forest, not the trees. Hide unnecessary technical info. DisableDrafts bool `ini:"disable_drafts"` // Users diff --git a/templates/user/include/header.tmpl b/templates/user/include/header.tmpl index f7c06ef..d818336 100644 --- a/templates/user/include/header.tmpl +++ b/templates/user/include/header.tmpl @@ -104,7 +104,9 @@ Users Pages {{end}} + {{if not .Forest}} Monitor + {{end}} {{end}} From 0d79057bae1dfb571ec0e7e55b04be57332da2af Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 14 Feb 2020 16:13:54 -0500 Subject: [PATCH 03/17] Rename ReleaseURL() to ReleaseNotesURL() --- admin.go | 10 +++++----- templates/user/admin/app-updates.tmpl | 2 +- updates.go | 6 +++--- updates_test.go | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/admin.go b/admin.go index 8d71aad..e3a1b33 100644 --- a/admin.go +++ b/admin.go @@ -583,17 +583,17 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re p := struct { *UserPage - LastChecked string - LatestVersion string - LatestReleaseURL string - UpdateAvailable bool + LastChecked string + LatestVersion string + LatestReleaseNotesURL string + UpdateAvailable bool }{ UserPage: NewUserPage(app, r, u, "Updates", nil), } if app.cfg.App.UpdateChecks { p.LastChecked = app.updates.lastCheck.Format("January 2, 2006, 3:04 PM") p.LatestVersion = app.updates.LatestVersion() - p.LatestReleaseURL = app.updates.ReleaseURL() + p.LatestReleaseNotesURL = app.updates.ReleaseNotesURL() p.UpdateAvailable = app.updates.AreAvailable() } diff --git a/templates/user/admin/app-updates.tmpl b/templates/user/admin/app-updates.tmpl index 540fb7c..3988a50 100644 --- a/templates/user/admin/app-updates.tmpl +++ b/templates/user/admin/app-updates.tmpl @@ -12,7 +12,7 @@ {{else}}

WriteFreely {{.LatestVersion}} is available.

- For details on features, bug fixes or notes on upgrading, read the release notes. + For details on features, bug fixes or notes on upgrading, read the release notes.
{{end}}

Last checked at: {{.LastChecked}}. Check now.

diff --git a/updates.go b/updates.go index c33247b..3a14233 100644 --- a/updates.go +++ b/updates.go @@ -1,5 +1,5 @@ /* - * Copyright © 2018-2019 A Bunch Tell LLC. + * Copyright © 2019-2020 A Bunch Tell LLC. * * This file is part of WriteFreely. * @@ -63,9 +63,9 @@ func (uc updatesCache) LatestVersion() string { return uc.latestVersion } -// ReleaseURL returns the full URL to the blog.writefreely.org release notes +// ReleaseNotesURL returns the full URL to the blog.writefreely.org release notes // for the latest version as stored in the cache. -func (uc updatesCache) ReleaseURL() string { +func (uc updatesCache) ReleaseNotesURL() string { ver := strings.TrimPrefix(uc.latestVersion, "v") ver = strings.TrimSuffix(ver, ".0") // hack until go 1.12 in build/travis diff --git a/updates_test.go b/updates_test.go index 2cb9f92..1c63f30 100644 --- a/updates_test.go +++ b/updates_test.go @@ -24,7 +24,7 @@ func TestUpdatesRoundTrip(t *testing.T) { }) t.Run("Release URL", func(t *testing.T) { - url := cache.ReleaseURL() + url := cache.ReleaseNotesURL() reg, err := regexp.Compile(`^https:\/\/blog.writefreely.org\/version(-\d+){1,}$`) if err != nil { From 602cd800202526ead1df9499944b91856dd6c604 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 14 Feb 2020 16:26:13 -0500 Subject: [PATCH 04/17] Fix mismatched span in user/admin/users.tmpl --- templates/user/admin/users.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/user/admin/users.tmpl b/templates/user/admin/users.tmpl index fb69d3a..51dd54a 100644 --- a/templates/user/admin/users.tmpl +++ b/templates/user/admin/users.tmpl @@ -4,7 +4,7 @@
{{template "admin-header" .}} -

Users {{.TotalUsers}} total

+

Users {{.TotalUsers}} total

From 68e992a55e4037bdc0dc24de9939d9119c8a7464 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sat, 15 Feb 2020 11:28:06 -0500 Subject: [PATCH 05/17] Fix bad #status anchor in view-user.tmpl --- templates/user/admin/view-user.tmpl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/templates/user/admin/view-user.tmpl b/templates/user/admin/view-user.tmpl index 8e5d87b..95bc416 100644 --- a/templates/user/admin/view-user.tmpl +++ b/templates/user/admin/view-user.tmpl @@ -71,8 +71,7 @@ input.copy-text { - - +
StatusStatus {{if .User.IsSilenced}}

Silenced

From 48ca695c463afdbe7ac6e96d2a0b1c8f83439685 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sat, 15 Feb 2020 11:57:55 -0500 Subject: [PATCH 06/17] Show last update check time in local timezone --- admin.go | 2 ++ templates/user/admin/app-updates.tmpl | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/admin.go b/admin.go index e3a1b33..7be67e9 100644 --- a/admin.go +++ b/admin.go @@ -584,6 +584,7 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re p := struct { *UserPage LastChecked string + LastChecked8601 string LatestVersion string LatestReleaseNotesURL string UpdateAvailable bool @@ -592,6 +593,7 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re } if app.cfg.App.UpdateChecks { p.LastChecked = app.updates.lastCheck.Format("January 2, 2006, 3:04 PM") + p.LastChecked8601 = app.updates.lastCheck.Format("2006-01-02T15:04:05Z") p.LatestVersion = app.updates.LatestVersion() p.LatestReleaseNotesURL = app.updates.ReleaseNotesURL() p.UpdateAvailable = app.updates.AreAvailable() diff --git a/templates/user/admin/app-updates.tmpl b/templates/user/admin/app-updates.tmpl index 3988a50..5d91230 100644 --- a/templates/user/admin/app-updates.tmpl +++ b/templates/user/admin/app-updates.tmpl @@ -15,7 +15,14 @@ For details on features, bug fixes or notes on upgrading, read the release notes. {{end}} -

Last checked at: {{.LastChecked}}. Check now.

+

Last checked at: . Check now.

+ + {{template "footer" .}} From a06bb457de77d9d1c397c1552ed331ceedaa3a62 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sat, 15 Feb 2020 11:59:47 -0500 Subject: [PATCH 07/17] Change copy and design on WF Updates page - Tweak the copy - Include link to download latest release - Change the version status design a bit - Restyle some text --- admin.go | 2 ++ less/core.less | 5 +++++ templates/user/admin/app-updates.tmpl | 20 ++++++++++++-------- updates.go | 4 ++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/admin.go b/admin.go index 7be67e9..89621ae 100644 --- a/admin.go +++ b/admin.go @@ -586,6 +586,7 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re LastChecked string LastChecked8601 string LatestVersion string + LatestReleaseURL string LatestReleaseNotesURL string UpdateAvailable bool }{ @@ -595,6 +596,7 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re p.LastChecked = app.updates.lastCheck.Format("January 2, 2006, 3:04 PM") p.LastChecked8601 = app.updates.lastCheck.Format("2006-01-02T15:04:05Z") p.LatestVersion = app.updates.LatestVersion() + p.LatestReleaseURL = app.updates.ReleaseURL() p.LatestReleaseNotesURL = app.updates.ReleaseNotesURL() p.UpdateAvailable = app.updates.AreAvailable() } diff --git a/less/core.less b/less/core.less index fe8a28d..0e5798b 100644 --- a/less/core.less +++ b/less/core.less @@ -1345,6 +1345,11 @@ div.row { } } +.check { + font-size: 1.125em; + color: #71D571; +} + @media all and (max-width: 450px) { body#post { header { diff --git a/templates/user/admin/app-updates.tmpl b/templates/user/admin/app-updates.tmpl index 5d91230..c7d9913 100644 --- a/templates/user/admin/app-updates.tmpl +++ b/templates/user/admin/app-updates.tmpl @@ -2,20 +2,24 @@ {{template "header" .}}
{{template "admin-header" .}} {{if not .UpdateAvailable}} -

WriteFreely is up to date.

- {{else}} -

WriteFreely {{.LatestVersion}} is available.

-
- For details on features, bug fixes or notes on upgrading, read the release notes. -
- {{end}} -

Last checked at: . Check now.

+

WriteFreely is up to date.

+

Installed version: {{.Version}} (release notes).

+ {{else}} +

A new version of WriteFreely is available! Get {{.LatestVersion}}

+

+ Read the release notes for details on features, bug fixes, and notes on upgrading from your current version, {{.Version}}. +

+ {{end}} +

Last checked: . Check now.

+{{ else }} +

Automated update checks are disabled.

+

Installed version: {{.Version}} (release notes).

+

Learn about latest releases on the WriteFreely blog or forum.

+{{ end }} {{template "footer" .}} diff --git a/updates.go b/updates.go index eba4810..e8f0d21 100644 --- a/updates.go +++ b/updates.go @@ -70,7 +70,11 @@ func (uc updatesCache) ReleaseURL() string { // ReleaseNotesURL returns the full URL to the blog.writefreely.org release notes // for the latest version as stored in the cache. func (uc updatesCache) ReleaseNotesURL() string { - ver := strings.TrimPrefix(uc.latestVersion, "v") + return wfReleaseNotesURL(uc.latestVersion) +} + +func wfReleaseNotesURL(v string) string { + ver := strings.TrimPrefix(v, "v") ver = strings.TrimSuffix(ver, ".0") // hack until go 1.12 in build/travis seg := strings.Split(ver, ".") From c2ece926e0bae96acfb9928860df35cbf121f278 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sat, 15 Feb 2020 12:53:47 -0500 Subject: [PATCH 09/17] Show update notification in admin nav bar When a WriteFreely update is available, indicate this on the "Updates" navigation item Ref T572 --- admin.go | 47 ++++++++++++++++++++++-------- less/admin.less | 6 ++++ less/core.less | 2 +- templates/user/include/header.tmpl | 2 +- updates.go | 6 ++++ 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/admin.go b/admin.go index 55cfb17..c0ad436 100644 --- a/admin.go +++ b/admin.go @@ -90,6 +90,16 @@ type instanceContent struct { Updated time.Time } +type AdminPage struct { + UpdateAvailable bool +} + +func NewAdminPage(app *App) *AdminPage { + return &AdminPage{ + UpdateAvailable: app.updates.AreAvailableNoCheck(), + } +} + func (c instanceContent) UpdatedFriendly() string { /* // TODO: accept a locale in this method and use that for the format @@ -102,12 +112,14 @@ func (c instanceContent) UpdatedFriendly() string { func handleViewAdminDash(app *App, u *User, w http.ResponseWriter, r *http.Request) error { p := struct { *UserPage + *AdminPage Message string UsersCount, CollectionsCount, PostsCount int64 }{ - UserPage: NewUserPage(app, r, u, "Admin", nil), - Message: r.FormValue("m"), + UserPage: NewUserPage(app, r, u, "Admin", nil), + AdminPage: NewAdminPage(app), + Message: r.FormValue("m"), } // Get user stats @@ -130,12 +142,14 @@ func handleViewAdminMonitor(app *App, u *User, w http.ResponseWriter, r *http.Re updateAppStats() p := struct { *UserPage + *AdminPage SysStatus systemStatus Config config.AppCfg Message, ConfigMessage string }{ UserPage: NewUserPage(app, r, u, "Admin", nil), + AdminPage: NewAdminPage(app), SysStatus: sysStatus, Config: app.cfg.App, @@ -150,12 +164,14 @@ func handleViewAdminMonitor(app *App, u *User, w http.ResponseWriter, r *http.Re func handleViewAdminSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) error { p := struct { *UserPage + *AdminPage Config config.AppCfg Message, ConfigMessage string }{ - UserPage: NewUserPage(app, r, u, "Admin", nil), - Config: app.cfg.App, + UserPage: NewUserPage(app, r, u, "Admin", nil), + AdminPage: NewAdminPage(app), + Config: app.cfg.App, Message: r.FormValue("m"), ConfigMessage: r.FormValue("cm"), @@ -168,6 +184,7 @@ func handleViewAdminSettings(app *App, u *User, w http.ResponseWriter, r *http.R func handleViewAdminUsers(app *App, u *User, w http.ResponseWriter, r *http.Request) error { p := struct { *UserPage + *AdminPage Config config.AppCfg Message string @@ -176,9 +193,10 @@ func handleViewAdminUsers(app *App, u *User, w http.ResponseWriter, r *http.Requ TotalUsers int64 TotalPages []int }{ - UserPage: NewUserPage(app, r, u, "Users", nil), - Config: app.cfg.App, - Message: r.FormValue("m"), + UserPage: NewUserPage(app, r, u, "Users", nil), + AdminPage: NewAdminPage(app), + Config: app.cfg.App, + Message: r.FormValue("m"), } p.TotalUsers = app.db.GetAllUsersCount() @@ -214,6 +232,7 @@ func handleViewAdminUser(app *App, u *User, w http.ResponseWriter, r *http.Reque p := struct { *UserPage + *AdminPage Config config.AppCfg Message string @@ -349,14 +368,16 @@ func handleAdminResetUserPass(app *App, u *User, w http.ResponseWriter, r *http. func handleViewAdminPages(app *App, u *User, w http.ResponseWriter, r *http.Request) error { p := struct { *UserPage + *AdminPage Config config.AppCfg Message string Pages []*instanceContent }{ - UserPage: NewUserPage(app, r, u, "Pages", nil), - Config: app.cfg.App, - Message: r.FormValue("m"), + UserPage: NewUserPage(app, r, u, "Pages", nil), + AdminPage: NewAdminPage(app), + Config: app.cfg.App, + Message: r.FormValue("m"), } var err error @@ -413,6 +434,7 @@ func handleViewAdminPage(app *App, u *User, w http.ResponseWriter, r *http.Reque p := struct { *UserPage + *AdminPage Config config.AppCfg Message string @@ -583,15 +605,16 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re p := struct { *UserPage + *AdminPage CurReleaseNotesURL string LastChecked string LastChecked8601 string LatestVersion string LatestReleaseURL string LatestReleaseNotesURL string - UpdateAvailable bool }{ - UserPage: NewUserPage(app, r, u, "Updates", nil), + UserPage: NewUserPage(app, r, u, "Updates", nil), + AdminPage: NewAdminPage(app), } p.CurReleaseNotesURL = wfReleaseNotesURL(p.Version) if app.cfg.App.UpdateChecks { diff --git a/less/admin.less b/less/admin.less index 3cbf30b..2aa34dc 100644 --- a/less/admin.less +++ b/less/admin.less @@ -19,8 +19,14 @@ nav#admin { &.selected { background: #dedede; font-weight: bold; + .blip { + color: black; + } } } + .blip { + font-weight: bold; + } } .pager { display: flex; diff --git a/less/core.less b/less/core.less index 0e5798b..05a050c 100644 --- a/less/core.less +++ b/less/core.less @@ -1345,7 +1345,7 @@ div.row { } } -.check { +.check, .blip { font-size: 1.125em; color: #71D571; } diff --git a/templates/user/include/header.tmpl b/templates/user/include/header.tmpl index 4b53b32..16978ee 100644 --- a/templates/user/include/header.tmpl +++ b/templates/user/include/header.tmpl @@ -103,7 +103,7 @@ {{if not .SingleUser}} Users Pages - {{if .UpdateChecks}}Updates{{end}} + {{if .UpdateChecks}}Updates{{if .UpdateAvailable}}!{{end}}{{end}} {{end}} {{if not .Forest}} Monitor diff --git a/updates.go b/updates.go index e8f0d21..b1893fd 100644 --- a/updates.go +++ b/updates.go @@ -58,6 +58,12 @@ func (uc updatesCache) AreAvailable() bool { return CompareSemver(uc.latestVersion, uc.currentVersion) == 1 } +// AreAvailableNoCheck returns if the latest release is newer than the current +// running version. +func (uc updatesCache) AreAvailableNoCheck() bool { + return CompareSemver(uc.latestVersion, uc.currentVersion) == 1 +} + // LatestVersion returns the latest stored version available. func (uc updatesCache) LatestVersion() string { return uc.latestVersion From 37b7755c08f80cddfa0487f2a72a6a3dd722dfaf Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sat, 15 Feb 2020 12:56:33 -0500 Subject: [PATCH 10/17] Tell admin that automated check failed when necessary This keeps track when automated update check fails, and displays a relevant message to the admin on /admin/updates Ref T572 --- admin.go | 2 ++ less/core.less | 5 +++++ templates/user/admin/app-updates.tmpl | 6 +++++- updates.go | 4 +++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/admin.go b/admin.go index c0ad436..b1f1533 100644 --- a/admin.go +++ b/admin.go @@ -612,6 +612,7 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re LatestVersion string LatestReleaseURL string LatestReleaseNotesURL string + CheckFailed bool }{ UserPage: NewUserPage(app, r, u, "Updates", nil), AdminPage: NewAdminPage(app), @@ -624,6 +625,7 @@ func handleViewAdminUpdates(app *App, u *User, w http.ResponseWriter, r *http.Re p.LatestReleaseURL = app.updates.ReleaseURL() p.LatestReleaseNotesURL = app.updates.ReleaseNotesURL() p.UpdateAvailable = app.updates.AreAvailable() + p.CheckFailed = app.updates.checkError != nil } showUserPage(w, "app-updates", p) diff --git a/less/core.less b/less/core.less index 05a050c..afccc9c 100644 --- a/less/core.less +++ b/less/core.less @@ -1350,6 +1350,11 @@ div.row { color: #71D571; } +.ex.failure { + font-weight: bold; + color: @dangerCol; +} + @media all and (max-width: 450px) { body#post { header { diff --git a/templates/user/admin/app-updates.tmpl b/templates/user/admin/app-updates.tmpl index 36e7f23..62fd83d 100644 --- a/templates/user/admin/app-updates.tmpl +++ b/templates/user/admin/app-updates.tmpl @@ -15,7 +15,11 @@ {{template "admin-header" .}} {{ if .UpdateChecks }} - {{if not .UpdateAvailable}} + {{if .CheckFailed}} +

× Automated update check failed.

+

Installed version: {{.Version}} (release notes).

+

Learn about latest releases on the WriteFreely blog or forum.

+ {{else if not .UpdateAvailable}}

WriteFreely is up to date.

Installed version: {{.Version}} (release notes).

{{else}} diff --git a/updates.go b/updates.go index b1893fd..e41b00b 100644 --- a/updates.go +++ b/updates.go @@ -30,6 +30,7 @@ type updatesCache struct { lastCheck time.Time latestVersion string currentVersion string + checkError error } // CheckNow asks for the latest released version of writefreely and updates @@ -38,11 +39,12 @@ type updatesCache struct { func (uc *updatesCache) CheckNow() error { uc.mu.Lock() defer uc.mu.Unlock() + uc.lastCheck = time.Now() latestRemote, err := newVersionCheck() if err != nil { + uc.checkError = err return err } - uc.lastCheck = time.Now() if CompareSemver(latestRemote, uc.latestVersion) == 1 { uc.latestVersion = latestRemote } From 987c74c93a33dd72de51c28ec1460c4577f05e3e Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sat, 15 Feb 2020 12:58:45 -0500 Subject: [PATCH 11/17] Add logging around automated update checks Logs requests when --debug enabled, and always logs errors from the check. Ref T572 --- updates.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/updates.go b/updates.go index e41b00b..9f4c3c0 100644 --- a/updates.go +++ b/updates.go @@ -11,6 +11,7 @@ package writefreely import ( + "github.com/writeas/web-core/log" "io/ioutil" "net/http" "strings" @@ -37,11 +38,15 @@ type updatesCache struct { // the cache last checked time. If the version postdates the current 'latest' // the version value is replaced. func (uc *updatesCache) CheckNow() error { + if debugging { + log.Info("[update check] Checking for update now.") + } uc.mu.Lock() defer uc.mu.Unlock() uc.lastCheck = time.Now() latestRemote, err := newVersionCheck() if err != nil { + log.Error("[update check] Failed: %v", err) uc.checkError = err return err } @@ -109,6 +114,9 @@ func (app *App) InitUpdates() { func newVersionCheck() (string, error) { res, err := http.Get("https://version.writefreely.org") + if debugging { + log.Info("[update check] GET https://version.writefreely.org") + } if err == nil && res.StatusCode == http.StatusOK { defer res.Body.Close() From 8933076296c51d2a97710e82049838c5cbf1e79e Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Tue, 25 Feb 2020 13:06:55 -0500 Subject: [PATCH 12/17] Add invite button to admin Users page header Ref T694 --- less/admin.less | 7 +++++++ less/core.less | 2 +- templates/user/admin/users.tmpl | 5 ++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/less/admin.less b/less/admin.less index 2aa34dc..ec49292 100644 --- a/less/admin.less +++ b/less/admin.less @@ -48,3 +48,10 @@ nav#admin { } } } + +.admin-actions { + .btn { + font-family: @sansFont; + font-size: 0.86em; + } +} \ No newline at end of file diff --git a/less/core.less b/less/core.less index afccc9c..231f373 100644 --- a/less/core.less +++ b/less/core.less @@ -1421,7 +1421,7 @@ div.row { } @media all and (max-width: 600px) { - div.row { + div.row:not(.admin-actions) { flex-direction: column; } .half { diff --git a/templates/user/admin/users.tmpl b/templates/user/admin/users.tmpl index 51dd54a..714fa24 100644 --- a/templates/user/admin/users.tmpl +++ b/templates/user/admin/users.tmpl @@ -4,7 +4,10 @@
{{template "admin-header" .}} -

Users {{.TotalUsers}} total

+
+ {{.TotalUsers}} {{pluralize "user" "users" .TotalUsers}} + + Invite people +
From d17e82d34c39c79c48b0b091cd3b2fd805c90b0c Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Tue, 25 Feb 2020 14:12:54 -0500 Subject: [PATCH 13/17] Prevent update check from slowing app init Previously, we'd wait for a response before finishing app initialization, meaning an overall slower startup. This fixes that. Ref T572 --- updates.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/updates.go b/updates.go index 9f4c3c0..8ecccf6 100644 --- a/updates.go +++ b/updates.go @@ -100,7 +100,7 @@ func newUpdatesCache(expiry time.Duration) *updatesCache { frequency: expiry, currentVersion: "v" + softwareVer, } - cache.CheckNow() + go cache.CheckNow() return &cache } @@ -117,6 +117,7 @@ func newVersionCheck() (string, error) { if debugging { log.Info("[update check] GET https://version.writefreely.org") } + // TODO: return error if statusCode != OK if err == nil && res.StatusCode == http.StatusOK { defer res.Body.Close() From 46dbb10433392a53abe715013a01ea63a0589d7a Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Tue, 25 Feb 2020 14:28:34 -0500 Subject: [PATCH 14/17] Make Admin Settings page more user-friendly - Add a description to each config item - Change item names to make more sense Ref T694 --- less/admin.less | 29 +++++ less/core.less | 14 --- templates/user/admin/app-settings.tmpl | 147 ++++++++++++++++++------- 3 files changed, 137 insertions(+), 53 deletions(-) diff --git a/less/admin.less b/less/admin.less index ec49292..d9d659e 100644 --- a/less/admin.less +++ b/less/admin.less @@ -54,4 +54,33 @@ nav#admin { font-family: @sansFont; font-size: 0.86em; } +} + +.features { + margin: 1em 0; + + div { + &:first-child { + font-weight: bold; + } + &+div { + padding-left: 1em; + } + + p { + font-weight: normal; + margin: 0.5rem 0; + font-size: 0.86em; + color: #666; + } + } +} + +@media (max-width: 600px) { + div.row.features { + align-items: start; + } + .features div + div { + padding-left: 0; + } } \ No newline at end of file diff --git a/less/core.less b/less/core.less index 231f373..7232660 100644 --- a/less/core.less +++ b/less/core.less @@ -868,20 +868,6 @@ input { text-align: center; } } - div.features { - margin-top: 1.5em; - text-align: center; - font-size: 0.86em; - ul { - text-align: left; - max-width: 26em; - margin-left: auto !important; - margin-right: auto !important; - li.soon, span.soon { - color: lighten(#111, 40%); - } - } - } div.blurbs { >h2 { text-align: center; diff --git a/templates/user/admin/app-settings.tmpl b/templates/user/admin/app-settings.tmpl index 4af6a44..3e0fdf7 100644 --- a/templates/user/admin/app-settings.tmpl +++ b/templates/user/admin/app-settings.tmpl @@ -24,55 +24,124 @@ p.docs { {{if .ConfigMessage}}

{{.ConfigMessage}}

{{end}} -

Read more in the configuration docs.

- -
-
-
+ +
+
+