From e02ec1cd710660a5f1e30d4e170af55e5fd851e6 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Thu, 27 Jan 2022 18:17:44 +0100 Subject: [PATCH] Replace more templates --- docs/usage.md | 2 +- editorFiles.go | 12 +- go.mod | 2 +- go.sum | 4 +- indieAuthServer.go | 2 +- notifications.go | 14 +-- postsDb.go | 11 +- postsDb_test.go | 4 +- render.go | 13 +- templates/editorfiles.gohtml | 29 ----- templates/indieauth.gohtml | 33 ----- templates/notificationsadmin.gohtml | 29 ----- ui.go | 185 +++++++++++++++++++++++++--- uiComponents.go | 18 +++ 14 files changed, 221 insertions(+), 137 deletions(-) delete mode 100644 templates/editorfiles.gohtml delete mode 100644 templates/indieauth.gohtml delete mode 100644 templates/notificationsadmin.gohtml diff --git a/docs/usage.md b/docs/usage.md index a1bfd1d..ab14214 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,6 +1,6 @@ # How to use GoBlog -This section of the documentation is a work in progress! +This section of the documentation is a **work in progress**! ## Posting diff --git a/editorFiles.go b/editorFiles.go index aefe875..2f0fcf4 100644 --- a/editorFiles.go +++ b/editorFiles.go @@ -16,8 +16,8 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) { } // Check if files at all if len(files) == 0 { - a.render(w, r, templateEditorFiles, &renderData{ - Data: map[string]interface{}{}, + a.renderNew(w, r, a.renderEditorFiles, &renderData{ + Data: &editorFilesRenderData{}, }) return } @@ -39,10 +39,10 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) { return } // Serve HTML - a.render(w, r, templateEditorFiles, &renderData{ - Data: map[string]interface{}{ - "Files": files, - "Uses": uses, + a.renderNew(w, r, a.renderEditorFiles, &renderData{ + Data: &editorFilesRenderData{ + files: files, + uses: uses, }, }) } diff --git a/go.mod b/go.mod index a02d34e..86d0eea 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( // master github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 - golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce + golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/text v0.3.7 diff --git a/go.sum b/go.sum index 3a097d5..099479c 100644 --- a/go.sum +++ b/go.sum @@ -472,8 +472,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= -golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 h1:kACShD3qhmr/3rLmg1yXyt+N4HcwutKyPRB93s54TIU= +golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= diff --git a/indieAuthServer.go b/indieAuthServer.go index 7c6d586..f1859f1 100644 --- a/indieAuthServer.go +++ b/indieAuthServer.go @@ -31,7 +31,7 @@ func (a *goBlog) indieAuthRequest(w http.ResponseWriter, r *http.Request) { return } // Render page that let's the user authorize the app - a.render(w, r, templateIndieAuth, &renderData{ + a.renderNew(w, r, a.renderIndieAuth, &renderData{ Data: iareq, }) } diff --git a/notifications.go b/notifications.go index ae3eeaf..a82f382 100644 --- a/notifications.go +++ b/notifications.go @@ -154,13 +154,13 @@ func (a *goBlog) notificationsAdmin(w http.ResponseWriter, r *http.Request) { } nextPath = fmt.Sprintf("%s/page/%d", notificationsPath, nextPage) // Render - a.render(w, r, templateNotificationsAdmin, &renderData{ - Data: map[string]interface{}{ - "Notifications": notifications, - "HasPrev": hasPrev, - "HasNext": hasNext, - "Prev": prevPath, - "Next": nextPath, + a.renderNew(w, r, a.renderNotificationsAdmin, &renderData{ + Data: ¬ificationsRenderData{ + notifications: notifications, + hasPrev: hasPrev, + hasNext: hasNext, + prev: prevPath, + next: nextPath, }, }) } diff --git a/postsDb.go b/postsDb.go index 0e9c192..b971659 100644 --- a/postsDb.go +++ b/postsDb.go @@ -628,7 +628,7 @@ select name, count(path) as count from ( group by name; ` -func (db *database) usesOfMediaFile(names ...string) (counts map[string]int, err error) { +func (db *database) usesOfMediaFile(names ...string) (counts []int, err error) { sqlArgs := []interface{}{dbNoCache} var nameValues strings.Builder for i, n := range names { @@ -645,7 +645,7 @@ func (db *database) usesOfMediaFile(names ...string) (counts map[string]int, err if err != nil { return nil, err } - counts = map[string]int{} + counts = make([]int, len(names)) var name string var count int for rows.Next() { @@ -653,7 +653,12 @@ func (db *database) usesOfMediaFile(names ...string) (counts map[string]int, err if err != nil { return nil, err } - counts[name] = count + for i, n := range names { + if n == name { + counts[i] = count + break + } + } } return counts, nil } diff --git a/postsDb_test.go b/postsDb_test.go index 82c2b11..4767cc5 100644 --- a/postsDb_test.go +++ b/postsDb_test.go @@ -358,7 +358,7 @@ func Test_usesOfMediaFile(t *testing.T) { counts, err := app.db.usesOfMediaFile("test.jpg") require.NoError(t, err) assert.Len(t, counts, 1) - if assert.NotNil(t, counts["test.jpg"]) { - assert.Equal(t, 2, counts["test.jpg"]) + if assert.NotEmpty(t, counts) { + assert.Equal(t, 2, counts[0]) } } diff --git a/render.go b/render.go index 342b385..8a88967 100644 --- a/render.go +++ b/render.go @@ -16,13 +16,10 @@ const ( templatesDir = "templates" templatesExt = ".gohtml" - templateBase = "base" - templateEditor = "editor" - templateEditorFiles = "editorfiles" - templateCommentsAdmin = "commentsadmin" - templateNotificationsAdmin = "notificationsadmin" - templateWebmentionAdmin = "webmentionadmin" - templateIndieAuth = "indieauth" + templateBase = "base" + templateEditor = "editor" + templateCommentsAdmin = "commentsadmin" + templateWebmentionAdmin = "webmentionadmin" ) func (a *goBlog) initRendering() error { @@ -42,14 +39,12 @@ func (a *goBlog) initRendering() error { }, // Others "dateformat": dateFormat, - "isodate": isoDateFormat, "unixtodate": unixToLocalDateString, "now": localNowString, "asset": a.assetFileName, "string": a.ts.GetTemplateStringVariantFunc(), "absolute": a.getFullAddress, "opensearch": openSearchUrl, - "mbytes": mBytesString, "editortemplate": a.editorPostTemplate, "editorpostdesc": a.editorPostDesc, } diff --git a/templates/editorfiles.gohtml b/templates/editorfiles.gohtml deleted file mode 100644 index 86db73d..0000000 --- a/templates/editorfiles.gohtml +++ /dev/null @@ -1,29 +0,0 @@ -{{ define "title" }} - {{ string .Blog.Lang "mediafiles" }} - {{ mdtitle .Blog.Title }} -{{ end }} - -{{ define "main" }} -
- {{ $blog := .Blog }} -

{{ string .Blog.Lang "mediafiles" }}

- {{ if .Data.Files }} -
- - - -
- - {{ else }} -

{{ string .Blog.Lang "nofiles" }}

- {{ end }} -
-{{ end }} - -{{ define "editorfiles" }} - {{ template "base" . }} -{{ end }} \ No newline at end of file diff --git a/templates/indieauth.gohtml b/templates/indieauth.gohtml deleted file mode 100644 index c372dc0..0000000 --- a/templates/indieauth.gohtml +++ /dev/null @@ -1,33 +0,0 @@ -{{ define "title" }} - {{ string .Blog.Lang "indieauth" }} - {{ .Blog.Title }} -{{ end }} - -{{ define "main" }} -
-

{{ string .Blog.Lang "indieauth" }}

-
-
- {{ if .Data.Scopes }} -

{{ string .Blog.Lang "scopes" }}

-
    - {{ range $i, $scope := .Data.Scopes }} -
  • - {{ end }} -
- {{ end }} -

client_id: {{ .Data.ClientID }}

-

redirect_uri: {{ .Data.RedirectURI }}

- - - - - - -
-
-
-{{ end }} - -{{ define "indieauth" }} - {{ template "base" . }} -{{ end }} \ No newline at end of file diff --git a/templates/notificationsadmin.gohtml b/templates/notificationsadmin.gohtml deleted file mode 100644 index b4ac168..0000000 --- a/templates/notificationsadmin.gohtml +++ /dev/null @@ -1,29 +0,0 @@ -{{ define "title" }} - {{ string "notifications" }} - {{ mdtitle .Blog.Title }} -{{ end }} - -{{ define "main" }} -
-

{{ string "notifications" }}

- {{ range $i, $notification := .Data.Notifications }} -
-

{{ unixtodate $notification.Time }}

- {{ md $notification.Text }} -
- - -
-
- {{ end }} - {{ if .Data.HasPrev }} -

{{ string "prev" }}

- {{ end }} - {{ if .Data.HasNext }} -

{{ string "next" }}

- {{ end }} -
-{{ end }} - -{{ define "notificationsadmin" }} - {{ template "base" . }} -{{ end }} \ No newline at end of file diff --git a/ui.go b/ui.go index 554283a..5d1ca52 100644 --- a/ui.go +++ b/ui.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/hacdias/indieauth" "github.com/kaorimatz/go-opml" "github.com/thoas/go-funk" ) @@ -398,20 +399,7 @@ func (a *goBlog) renderIndex(hb *htmlBuilder, rd *renderData) { hb.writeElementClose("p") } // Navigation - if id.hasPrev { - hb.writeElementOpen("p") - hb.writeElementOpen("a", "href", id.prev) // TODO: rel=prev? - hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "prev")) - hb.writeElementClose("a") - hb.writeElementClose("p") - } - if id.hasNext { - hb.writeElementOpen("p") - hb.writeElementOpen("a", "href", id.next) // TODO: rel=next? - hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "next")) - hb.writeElementClose("a") - hb.writeElementClose("p") - } + a.renderPagination(hb, rd.Blog, id.hasPrev, id.hasNext, id.prev, id.next) // Author a.renderAuthor(hb) hb.writeElementClose("main") @@ -1054,3 +1042,172 @@ func (a *goBlog) renderStaticHome(hb *htmlBuilder, rd *renderData) { }, ) } + +func (a *goBlog) renderIndieAuth(hb *htmlBuilder, rd *renderData) { + indieAuthRequest, ok := rd.Data.(*indieauth.AuthenticationRequest) + if !ok { + return + } + a.renderBase( + hb, rd, + func(hb *htmlBuilder) { + a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "indieauth")) + }, + func(hb *htmlBuilder) { + hb.writeElementOpen("main") + // Title + hb.writeElementOpen("h1") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "indieauth")) + hb.writeElementClose("h1") + hb.writeElementClose("main") + // Form + hb.writeElementOpen("form", "method", "post", "action", "/indieauth/accept", "class", "p") + // Scopes + if scopes := indieAuthRequest.Scopes; len(scopes) > 0 { + hb.writeElementOpen("h3") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "scopes")) + hb.writeElementClose("h3") + hb.writeElementOpen("ul") + for _, scope := range scopes { + hb.writeElementOpen("li") + hb.writeElementOpen("input", "type", "checkbox", "name", "scopes", "value", scope, "id", "scope-"+scope, "checked", "") + hb.writeElementOpen("label", "for", "scope-"+scope) + hb.writeEscaped(scope) + hb.writeElementClose("label") + hb.writeElementClose("li") + } + hb.writeElementClose("ul") + } + // Client ID + hb.writeElementOpen("p") + hb.writeElementOpen("strong") + hb.writeEscaped("client_id:") + hb.writeElementClose("strong") + hb.write(" ") + hb.writeEscaped(indieAuthRequest.ClientID) + hb.writeElementClose("p") + // Redirect URI + hb.writeElementOpen("p") + hb.writeElementOpen("strong") + hb.writeEscaped("redirect_uri:") + hb.writeElementClose("strong") + hb.write(" ") + hb.writeEscaped(indieAuthRequest.RedirectURI) + hb.writeElementClose("p") + // Hidden form fields + hb.writeElementOpen("input", "type", "hidden", "name", "client_id", "value", indieAuthRequest.ClientID) + hb.writeElementOpen("input", "type", "hidden", "name", "redirect_uri", "value", indieAuthRequest.RedirectURI) + hb.writeElementOpen("input", "type", "hidden", "name", "state", "value", indieAuthRequest.State) + hb.writeElementOpen("input", "type", "hidden", "name", "code_challenge", "value", indieAuthRequest.CodeChallenge) + hb.writeElementOpen("input", "type", "hidden", "name", "code_challenge_method", "value", indieAuthRequest.CodeChallengeMethod) + // Submit button + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "authenticate")) + hb.writeElementClose("form") + }, + ) +} + +type editorFilesRenderData struct { + files []*mediaFile + uses []int +} + +func (a *goBlog) renderEditorFiles(hb *htmlBuilder, rd *renderData) { + ef, ok := rd.Data.(*editorFilesRenderData) + if !ok { + return + } + a.renderBase( + hb, rd, + func(hb *htmlBuilder) { + a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "mediafiles")) + }, + func(hb *htmlBuilder) { + hb.writeElementOpen("main") + // Title + hb.writeElementOpen("h1") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "mediafiles")) + hb.writeElementClose("h1") + // Files + if len(ef.files) > 0 { + // Form + hb.writeElementOpen("form", "method", "post", "class", "fw p") + // Select with number of uses + hb.writeElementOpen("select", "name", "filename") + usesString := a.ts.GetTemplateStringVariant(rd.Blog.Lang, "fileuses") + for i, f := range ef.files { + hb.writeElementOpen("option", "value", f.Name) + hb.writeEscaped(fmt.Sprintf("%s (%s), %s, ~%d %s", f.Name, isoDateFormat(f.Time.String()), mBytesString(f.Size), ef.uses[i], usesString)) + hb.writeElementClose("option") + } + hb.writeElementClose("select") + // View button + hb.writeElementOpen( + "input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "view"), + "formaction", rd.Blog.getRelativePath("/editor/files/view"), + ) + // Delete button + hb.writeElementOpen( + "input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete"), + "formaction", rd.Blog.getRelativePath("/editor/files/delete"), + "class", "confirm", "data-confirmmessage", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "confirmdelete"), + ) + hb.writeElementOpen("script", "src", a.assetFileName("js/formconfirm.js"), "defer", "") + hb.writeElementClose("script") + hb.writeElementClose("form") + } else { + hb.writeElementOpen("p") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "nofiles")) + hb.writeElementClose("p") + } + hb.writeElementClose("main") + }, + ) +} + +type notificationsRenderData struct { + notifications []*notification + hasPrev, hasNext bool + prev, next string +} + +func (a *goBlog) renderNotificationsAdmin(hb *htmlBuilder, rd *renderData) { + nrd, ok := rd.Data.(*notificationsRenderData) + if !ok { + return + } + a.renderBase( + hb, rd, + func(hb *htmlBuilder) { + a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "notifications")) + }, + func(hb *htmlBuilder) { + hb.writeElementOpen("main") + // Title + hb.writeElementOpen("h1") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "notifications")) + hb.writeElementClose("h1") + // Notifications + for _, n := range nrd.notifications { + hb.writeElementOpen("div", "class", "p") + // Date + hb.writeElementOpen("p") + hb.writeElementOpen("i") + hb.writeEscaped(unixToLocalDateString(n.Time)) + hb.writeElementClose("i") + hb.writeElementClose("p") + // Message + a.renderMarkdownToWriter(hb, n.Text, false) + // Delete form + hb.writeElementOpen("form", "method", "post", "action", "/notifications/delete") + hb.writeElementOpen("input", "type", "hidden", "name", "notificationid", "value", n.ID) + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete")) + hb.writeElementClose("form") + hb.writeElementClose("div") + } + // Pagination + a.renderPagination(hb, rd.Blog, nrd.hasPrev, nrd.hasNext, nrd.prev, nrd.next) + hb.writeElementClose("main") + }, + ) +} diff --git a/uiComponents.go b/uiComponents.go index 16a31c3..2cf6989 100644 --- a/uiComponents.go +++ b/uiComponents.go @@ -384,3 +384,21 @@ func (a *goBlog) renderTitleTag(hb *htmlBuilder, blog *configBlog, optionalTitle hb.writeEscaped(a.renderMdTitle(blog.Title)) hb.writeElementClose("title") } + +func (a *goBlog) renderPagination(hb *htmlBuilder, blog *configBlog, hasPrev, hasNext bool, prev, next string) { + // Navigation + if hasPrev { + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", prev) // TODO: rel=prev? + hb.writeEscaped(a.ts.GetTemplateStringVariant(blog.Lang, "prev")) + hb.writeElementClose("a") + hb.writeElementClose("p") + } + if hasNext { + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", next) // TODO: rel=next? + hb.writeEscaped(a.ts.GetTemplateStringVariant(blog.Lang, "next")) + hb.writeElementClose("a") + hb.writeElementClose("p") + } +}