diff --git a/history/histview/histview.go b/history/histview/histview.go new file mode 100644 index 0000000..25dbea2 --- /dev/null +++ b/history/histview/histview.go @@ -0,0 +1,87 @@ +// Package histview provides web stuff for history +package histview + +import ( + "embed" + "encoding/hex" + "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/history" + "github.com/bouncepaw/mycorrhiza/hyphae" + "github.com/bouncepaw/mycorrhiza/util" + "github.com/bouncepaw/mycorrhiza/viewutil" + "github.com/gorilla/mux" + "log" + "net/http" + "strings" + "text/template" +) + +func InitHandlers(rtr *mux.Router) { + rtr.PathPrefix("/primitive-diff/").HandlerFunc(handlerPrimitiveDiff) + chainPrimitiveDiff = viewutil. + En(viewutil.CopyEnWith(fs, "view_primitive_diff.html")). + Ru(template.Must(viewutil.CopyRuWith(fs, "view_primitive_diff.html").Parse(ruTranslation))) +} + +func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + shorterURL := strings.TrimPrefix(rq.URL.Path, "/primitive-diff/") + revHash, slug, found := strings.Cut(shorterURL, "/") + if !found || len(revHash) < 7 || len(slug) < 1 { + http.Error(w, "403 bad request", http.StatusBadRequest) + return + } + paddedRevHash := revHash + if len(paddedRevHash)%2 != 0 { + paddedRevHash = paddedRevHash[:len(paddedRevHash)-1] + } + if _, err := hex.DecodeString(paddedRevHash); err != nil { + http.Error(w, "403 bad request", http.StatusBadRequest) + return + } + switch h := hyphae.ByName(util.CanonicalName(slug)).(type) { + case *hyphae.EmptyHypha: + http.Error(w, "404 not found", http.StatusNotFound) + case hyphae.ExistingHypha: + text, err := history.PrimitiveDiffAtRevision(h.TextFilePath(), revHash) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + primitiveDiff(viewutil.MetaFrom(w, rq), h, revHash, text) + } +} + +var ( + //go:embed *.html + fs embed.FS + ruTranslation = ` +{{define "diff for at title"}}Разница для {{beautifulName .HyphaName}} для {{.Hash}}{{end}} +{{define "diff for at heading"}}Разница для {{beautifulName .HyphaName}} для {{.Hash}}{{end}} + +` + chainPrimitiveDiff viewutil.Chain +) + +type primitiveDiffData struct { + viewutil.BaseData + HyphaName string + Hash string + Text string +} + +func primitiveDiff(meta viewutil.Meta, h hyphae.ExistingHypha, hash, text string) { + if err := chainPrimitiveDiff.Get(meta).ExecuteTemplate(meta.W, "page", primitiveDiffData{ + BaseData: viewutil.BaseData{ + Meta: meta, + Addr: "/primitive-diff/" + hash + "/" + h.CanonicalName(), + HeaderLinks: cfg.HeaderLinks, + CommonScripts: cfg.CommonScripts, + }, + HyphaName: h.CanonicalName(), + Hash: hash, + Text: text, + }); err != nil { + log.Println(err) + } +} diff --git a/history/histview/view_primitive_diff.html b/history/histview/view_primitive_diff.html new file mode 100644 index 0000000..c2025a0 --- /dev/null +++ b/history/histview/view_primitive_diff.html @@ -0,0 +1,11 @@ +{{define "diff for at title"}}Diff of {{beautifulName .HyphaName}} at {{.Hash}}{{end}} +{{define "diff for at heading"}}Diff of {{beautifulName .HyphaName}} at {{.Hash}}{{end}} +{{define "title"}}{{template "diff for at title" .}}{{end}} +{{define "body"}} +
+
+

{{template "diff for at heading" .}}

+
{{.Text}}
+
+
+{{end}} \ No newline at end of file diff --git a/l18n/ru/ui.json b/l18n/ru/ui.json index 26a25ab..3c95c61 100644 --- a/l18n/ru/ui.json +++ b/l18n/ru/ui.json @@ -74,8 +74,6 @@ "recent_subscribe": "Подписаться через {{.rss}}, {{.atom}} или {{.json}}", "recent_subscribe_json": "JSON-ленту", "recent_empty": "Не удалось найти последние изменения.", - - "diff_title": "Разница для «{{.name}}» из {{.rev}}", "revision_title": "{{.name}} из {{.rev}}", "revision_warning": "Обратите внимание, просмотр медиа в истории пока что недоступен.", diff --git a/views/history.qtpl b/views/history.qtpl index 616b1f8..b28b00e 100644 --- a/views/history.qtpl +++ b/views/history.qtpl @@ -4,27 +4,9 @@ {% import "github.com/bouncepaw/mycorrhiza/cfg" %} {% import "github.com/bouncepaw/mycorrhiza/l18n" %} -{% import "github.com/bouncepaw/mycorrhiza/user" %} -{% import "github.com/bouncepaw/mycorrhiza/hyphae" %} {% import "github.com/bouncepaw/mycorrhiza/history" %} -{% func PrimitiveDiff(rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) %} -{% code -lc := l18n.FromRequest(rq) -text, err := history.PrimitiveDiffAtRevision(h.TextFilePath(), hash) -if err != nil { - text = err.Error() -} -%} -
-
-

{%s= lc.Get("ui.diff_title", &l18n.Replacements{"name": beautifulLink(h.CanonicalName()), "rev": hash}) %}

-
{%s text %}
-
-
-{% endfunc %} - {% func RecentChanges(n int, lc *l18n.Localizer) %}

{%s lc.Get("ui.recent_heading") %}

diff --git a/views/history.qtpl.go b/views/history.qtpl.go index e7291f1..490a401 100644 --- a/views/history.qtpl.go +++ b/views/history.qtpl.go @@ -20,422 +20,358 @@ import "github.com/bouncepaw/mycorrhiza/cfg" import "github.com/bouncepaw/mycorrhiza/l18n" //line views/history.qtpl:7 -import "github.com/bouncepaw/mycorrhiza/user" - -//line views/history.qtpl:8 -import "github.com/bouncepaw/mycorrhiza/hyphae" - -//line views/history.qtpl:9 import "github.com/bouncepaw/mycorrhiza/history" -//line views/history.qtpl:12 +//line views/history.qtpl:10 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/history.qtpl:12 +//line views/history.qtpl:10 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/history.qtpl:12 -func StreamPrimitiveDiff(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) { -//line views/history.qtpl:12 - qw422016.N().S(` -`) -//line views/history.qtpl:14 - lc := l18n.FromRequest(rq) - text, err := history.PrimitiveDiffAtRevision(h.TextFilePath(), hash) - if err != nil { - text = err.Error() - } - -//line views/history.qtpl:19 - qw422016.N().S(` -
-
-

`) -//line views/history.qtpl:22 - qw422016.N().S(lc.Get("ui.diff_title", &l18n.Replacements{"name": beautifulLink(h.CanonicalName()), "rev": hash})) -//line views/history.qtpl:22 - qw422016.N().S(`

-
`)
-//line views/history.qtpl:23
-	qw422016.E().S(text)
-//line views/history.qtpl:23
-	qw422016.N().S(`
-
-
-`) -//line views/history.qtpl:26 -} - -//line views/history.qtpl:26 -func WritePrimitiveDiff(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) { -//line views/history.qtpl:26 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:26 - StreamPrimitiveDiff(qw422016, rq, h, u, hash) -//line views/history.qtpl:26 - qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:26 -} - -//line views/history.qtpl:26 -func PrimitiveDiff(rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) string { -//line views/history.qtpl:26 - qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:26 - WritePrimitiveDiff(qb422016, rq, h, u, hash) -//line views/history.qtpl:26 - qs422016 := string(qb422016.B) -//line views/history.qtpl:26 - qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:26 - return qs422016 -//line views/history.qtpl:26 -} - -//line views/history.qtpl:28 +//line views/history.qtpl:10 func StreamRecentChanges(qw422016 *qt422016.Writer, n int, lc *l18n.Localizer) { -//line views/history.qtpl:28 +//line views/history.qtpl:10 qw422016.N().S(`

`) -//line views/history.qtpl:30 +//line views/history.qtpl:12 qw422016.E().S(lc.Get("ui.recent_heading")) -//line views/history.qtpl:30 +//line views/history.qtpl:12 qw422016.N().S(`

`) -//line views/history.qtpl:47 +//line views/history.qtpl:29 qw422016.N().S(lc.Get("ui.recent_subscribe", &l18n.Replacements{"rss": "RSS", "atom": "Atom", "json": fmt.Sprintf("%s", lc.Get("ui.recent_subscribe_json"))})) -//line views/history.qtpl:47 +//line views/history.qtpl:29 qw422016.N().S(`

`) -//line views/history.qtpl:54 +//line views/history.qtpl:36 qw422016.N().S(` `) -//line views/history.qtpl:57 +//line views/history.qtpl:39 changes := history.RecentChanges(n) var year, day int var month time.Month -//line views/history.qtpl:60 +//line views/history.qtpl:42 qw422016.N().S(`
`) -//line views/history.qtpl:62 +//line views/history.qtpl:44 if len(changes) == 0 { -//line views/history.qtpl:62 +//line views/history.qtpl:44 qw422016.N().S(`

`) -//line views/history.qtpl:63 +//line views/history.qtpl:45 qw422016.E().S(lc.Get("ui.recent_empty")) -//line views/history.qtpl:63 +//line views/history.qtpl:45 qw422016.N().S(`

`) -//line views/history.qtpl:64 +//line views/history.qtpl:46 } else { -//line views/history.qtpl:64 +//line views/history.qtpl:46 qw422016.N().S(` `) -//line views/history.qtpl:65 +//line views/history.qtpl:47 for i, entry := range changes { -//line views/history.qtpl:65 +//line views/history.qtpl:47 qw422016.N().S(` `) -//line views/history.qtpl:67 +//line views/history.qtpl:49 y, m, d := entry.Time.UTC().Date() -//line views/history.qtpl:67 +//line views/history.qtpl:49 qw422016.N().S(` `) -//line views/history.qtpl:68 +//line views/history.qtpl:50 if d != day || m != month || y != year { -//line views/history.qtpl:68 +//line views/history.qtpl:50 qw422016.N().S(`

`) -//line views/history.qtpl:70 +//line views/history.qtpl:52 qw422016.E().S(fmt.Sprintf("%04d-%02d-%02d", y, m, d)) -//line views/history.qtpl:70 +//line views/history.qtpl:52 qw422016.N().S(`

`) -//line views/history.qtpl:72 +//line views/history.qtpl:54 year, month, day = y, m, d -//line views/history.qtpl:72 +//line views/history.qtpl:54 qw422016.N().S(` `) -//line views/history.qtpl:73 +//line views/history.qtpl:55 } -//line views/history.qtpl:73 +//line views/history.qtpl:55 qw422016.N().S(`
`) -//line views/history.qtpl:77 +//line views/history.qtpl:59 qw422016.N().S(recentChanges(entry)) -//line views/history.qtpl:77 +//line views/history.qtpl:59 qw422016.N().S(`
`) -//line views/history.qtpl:80 +//line views/history.qtpl:62 } -//line views/history.qtpl:80 +//line views/history.qtpl:62 qw422016.N().S(` `) -//line views/history.qtpl:81 +//line views/history.qtpl:63 } -//line views/history.qtpl:81 +//line views/history.qtpl:63 qw422016.N().S(`
`) -//line views/history.qtpl:84 +//line views/history.qtpl:66 } -//line views/history.qtpl:84 +//line views/history.qtpl:66 func WriteRecentChanges(qq422016 qtio422016.Writer, n int, lc *l18n.Localizer) { -//line views/history.qtpl:84 +//line views/history.qtpl:66 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:84 +//line views/history.qtpl:66 StreamRecentChanges(qw422016, n, lc) -//line views/history.qtpl:84 +//line views/history.qtpl:66 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:84 +//line views/history.qtpl:66 } -//line views/history.qtpl:84 +//line views/history.qtpl:66 func RecentChanges(n int, lc *l18n.Localizer) string { -//line views/history.qtpl:84 +//line views/history.qtpl:66 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:84 +//line views/history.qtpl:66 WriteRecentChanges(qb422016, n, lc) -//line views/history.qtpl:84 +//line views/history.qtpl:66 qs422016 := string(qb422016.B) -//line views/history.qtpl:84 +//line views/history.qtpl:66 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:84 +//line views/history.qtpl:66 return qs422016 -//line views/history.qtpl:84 +//line views/history.qtpl:66 } -//line views/history.qtpl:86 +//line views/history.qtpl:68 func streamrecentChanges(qw422016 *qt422016.Writer, rev history.Revision) { -//line views/history.qtpl:86 +//line views/history.qtpl:68 qw422016.N().S(`
`) -//line views/history.qtpl:91 +//line views/history.qtpl:73 qw422016.E().S(rev.Hash) -//line views/history.qtpl:91 +//line views/history.qtpl:73 qw422016.N().S(` `) -//line views/history.qtpl:93 +//line views/history.qtpl:75 if rev.Username != "anon" { -//line views/history.qtpl:93 +//line views/history.qtpl:75 qw422016.N().S(` `) -//line views/history.qtpl:97 +//line views/history.qtpl:79 } -//line views/history.qtpl:97 +//line views/history.qtpl:79 qw422016.N().S(`
`) -//line views/history.qtpl:101 +//line views/history.qtpl:83 qw422016.N().S(rev.HyphaeLinksHTML()) -//line views/history.qtpl:101 +//line views/history.qtpl:83 qw422016.N().S(` `) -//line views/history.qtpl:104 +//line views/history.qtpl:86 qw422016.E().S(rev.Message) -//line views/history.qtpl:104 +//line views/history.qtpl:86 qw422016.N().S(`
`) -//line views/history.qtpl:107 +//line views/history.qtpl:89 } -//line views/history.qtpl:107 +//line views/history.qtpl:89 func writerecentChanges(qq422016 qtio422016.Writer, rev history.Revision) { -//line views/history.qtpl:107 +//line views/history.qtpl:89 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:107 +//line views/history.qtpl:89 streamrecentChanges(qw422016, rev) -//line views/history.qtpl:107 +//line views/history.qtpl:89 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:107 +//line views/history.qtpl:89 } -//line views/history.qtpl:107 +//line views/history.qtpl:89 func recentChanges(rev history.Revision) string { -//line views/history.qtpl:107 +//line views/history.qtpl:89 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:107 +//line views/history.qtpl:89 writerecentChanges(qb422016, rev) -//line views/history.qtpl:107 +//line views/history.qtpl:89 qs422016 := string(qb422016.B) -//line views/history.qtpl:107 +//line views/history.qtpl:89 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:107 +//line views/history.qtpl:89 return qs422016 -//line views/history.qtpl:107 +//line views/history.qtpl:89 } -//line views/history.qtpl:109 +//line views/history.qtpl:91 func StreamHistory(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, list string, lc *l18n.Localizer) { -//line views/history.qtpl:109 +//line views/history.qtpl:91 qw422016.N().S(`

`) -//line views/history.qtpl:112 +//line views/history.qtpl:94 qw422016.N().S(fmt.Sprintf(lc.Get("ui.history_title"), beautifulLink(hyphaName))) -//line views/history.qtpl:112 +//line views/history.qtpl:94 qw422016.N().S(`

`) -//line views/history.qtpl:113 +//line views/history.qtpl:95 qw422016.N().S(list) -//line views/history.qtpl:113 +//line views/history.qtpl:95 qw422016.N().S(`
`) -//line views/history.qtpl:116 +//line views/history.qtpl:98 } -//line views/history.qtpl:116 +//line views/history.qtpl:98 func WriteHistory(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, list string, lc *l18n.Localizer) { -//line views/history.qtpl:116 +//line views/history.qtpl:98 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:116 +//line views/history.qtpl:98 StreamHistory(qw422016, rq, hyphaName, list, lc) -//line views/history.qtpl:116 +//line views/history.qtpl:98 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:116 +//line views/history.qtpl:98 } -//line views/history.qtpl:116 +//line views/history.qtpl:98 func History(rq *http.Request, hyphaName, list string, lc *l18n.Localizer) string { -//line views/history.qtpl:116 +//line views/history.qtpl:98 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:116 +//line views/history.qtpl:98 WriteHistory(qb422016, rq, hyphaName, list, lc) -//line views/history.qtpl:116 +//line views/history.qtpl:98 qs422016 := string(qb422016.B) -//line views/history.qtpl:116 +//line views/history.qtpl:98 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:116 +//line views/history.qtpl:98 return qs422016 -//line views/history.qtpl:116 +//line views/history.qtpl:98 } diff --git a/web/readers.go b/web/readers.go index 577f57b..d8fe26f 100644 --- a/web/readers.go +++ b/web/readers.go @@ -1,7 +1,6 @@ package web import ( - "encoding/hex" "fmt" "github.com/bouncepaw/mycomarkup/v4" "github.com/bouncepaw/mycorrhiza/shroom" @@ -34,7 +33,6 @@ func initReaders(r *mux.Router) { r.PathPrefix("/binary/").HandlerFunc(handlerBinary) r.PathPrefix("/rev/").HandlerFunc(handlerRevision) r.PathPrefix("/rev-text/").HandlerFunc(handlerRevisionText) - r.PathPrefix("/primitive-diff/").HandlerFunc(handlerPrimitiveDiff) r.PathPrefix("/media/").HandlerFunc(handlerMedia) } @@ -53,40 +51,6 @@ func handlerMedia(w http.ResponseWriter, rq *http.Request) { views.MediaMenu(rq, h, u))) } -func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { - util.PrepareRq(rq) - shorterURL := strings.TrimPrefix(rq.URL.Path, "/primitive-diff/") - revHash, slug, found := strings.Cut(shorterURL, "/") - if !found || len(revHash) < 7 || len(slug) < 1 { - http.Error(w, "403 bad request", http.StatusBadRequest) - return - } - paddedRevHash := revHash - if len(paddedRevHash)%2 != 0 { - paddedRevHash = paddedRevHash[:len(paddedRevHash)-1] - } - if _, err := hex.DecodeString(paddedRevHash); err != nil { - http.Error(w, "403 bad request", http.StatusBadRequest) - return - } - var ( - hyphaName = util.CanonicalName(slug) - h = hyphae.ByName(hyphaName) - user = user.FromRequest(rq) - lc = l18n.FromRequest(rq) - ) - switch h := h.(type) { - case *hyphae.EmptyHypha: - w.WriteHeader(http.StatusNotFound) - io.WriteString(w, "404 not found") - case hyphae.ExistingHypha: - util.HTTP200Page(w, views.Base( - viewutil.MetaFrom(w, rq), - lc.Get("ui.diff_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}), - views.PrimitiveDiff(rq, h, user, revHash))) - } -} - // handlerRevisionText sends Mycomarkup text of the hypha at the given revision. See also: handlerRevision, handlerText. // // /rev-text// diff --git a/web/web.go b/web/web.go index 9cf16b4..e2d2e9d 100644 --- a/web/web.go +++ b/web/web.go @@ -5,6 +5,7 @@ import ( "github.com/bouncepaw/mycorrhiza/backlinks" "github.com/bouncepaw/mycorrhiza/categories" "github.com/bouncepaw/mycorrhiza/help" + "github.com/bouncepaw/mycorrhiza/history/histview" "github.com/bouncepaw/mycorrhiza/hypview" "github.com/bouncepaw/mycorrhiza/misc" "io" @@ -54,6 +55,7 @@ func Handler() http.Handler { categories.InitHandlers(wikiRouter) misc.InitHandlers(wikiRouter) hypview.Init() + histview.InitHandlers(wikiRouter) // Admin routes. if cfg.UseAuth {