diff --git a/categories/handlers.go b/categories/handlers.go index 625ce66..db016ce 100644 --- a/categories/handlers.go +++ b/categories/handlers.go @@ -16,10 +16,22 @@ func InitHandlers(r *mux.Router) { r.PathPrefix("/add-to-category").HandlerFunc(handlerAddToCategory).Methods("POST") r.PathPrefix("/remove-from-category").HandlerFunc(handlerRemoveFromCategory).Methods("POST") r.PathPrefix("/category/").HandlerFunc(handlerCategory).Methods("GET") + r.PathPrefix("/edit-category/").HandlerFunc(handlerEditCategory).Methods("GET") r.PathPrefix("/category").HandlerFunc(handlerListCategory).Methods("GET") prepareViews() } +func handlerEditCategory(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + catName := util.CanonicalName(strings.TrimPrefix(strings.TrimPrefix(rq.URL.Path, "/edit-category"), "/")) + if catName == "" { + http.Error(w, "No category name", http.StatusBadRequest) + return + } + log.Println("Editing category", catName) + categoryEdit(viewutil.MetaFrom(w, rq), catName) +} + func handlerListCategory(w http.ResponseWriter, rq *http.Request) { log.Println("Viewing list of categories") categoryList(viewutil.MetaFrom(w, rq)) @@ -36,24 +48,54 @@ func handlerCategory(w http.ResponseWriter, rq *http.Request) { categoryPage(viewutil.MetaFrom(w, rq), catName) } +// A request for removal of hyphae can either remove one hypha (used in the card on /hypha) or many hyphae (used in /edit-category). Both approaches are handled by /remove-from-category. This function finds all passed hyphae. +// +// There is one hypha from the hypha field. Then there are n hyphae in fields prefixed by _. It seems like I have to do it myself. Compare with PHP which handles it for you. I hope I am doing this wrong. +func hyphaeFromRequest(rq *http.Request) (canonicalNames []string) { + if err := rq.ParseForm(); err != nil { + log.Println(err) + } + if hyphaName := util.CanonicalName(rq.PostFormValue("hypha")); hyphaName != "" { + canonicalNames = append(canonicalNames, hyphaName) + } + // According to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox, + // + // > If a checkbox is unchecked when its form is submitted, there is no value submitted to the server to represent its unchecked state + // + // It means, that if there is a value, it is checked. And we can ignore values altogether. + for key, _ := range rq.PostForm { + // No prefix or "_": + if !strings.HasPrefix(key, "_") || len(key) == 1 { + continue + } + canonicalNames = append(canonicalNames, util.CanonicalName(key[1:])) + } + return +} + func handlerRemoveFromCategory(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( - hyphaName = util.CanonicalName(rq.PostFormValue("hypha")) + u = user.FromRequest(rq) + hyphaNames = hyphaeFromRequest(rq) catName = util.CanonicalName(rq.PostFormValue("cat")) redirectTo = rq.PostFormValue("redirect-to") ) - if !user.FromRequest(rq).CanProceed("remove-from-category") { + if !u.CanProceed("remove-from-category") { w.WriteHeader(http.StatusForbidden) _, _ = io.WriteString(w, "403 Forbidden") return } - if hyphaName == "" || catName == "" { + if len(hyphaNames) == 0 || catName == "" { + log.Printf("%s passed no data for removal of hyphae from a category\n", u.Name) http.Redirect(w, rq, redirectTo, http.StatusSeeOther) return } - log.Println(user.FromRequest(rq).Name, "removed", hyphaName, "from", catName) - removeHyphaFromCategory(hyphaName, catName) + for _, hyphaName := range hyphaNames { + // TODO: Make it more effective. + removeHyphaFromCategory(hyphaName, catName) + } + log.Printf("%s removed %q from category %s\n", u.Name, hyphaNames, catName) http.Redirect(w, rq, redirectTo, http.StatusSeeOther) } diff --git a/categories/view_edit.html b/categories/view_edit.html new file mode 100644 index 0000000..02c3e51 --- /dev/null +++ b/categories/view_edit.html @@ -0,0 +1,35 @@ +{{define "edit category x"}}Edit category {{beautifulName .}}{{end}} +{{define "title"}}{{template "edit category x" .CatName}}{{end}} +{{define "body"}} +
+

{{block "edit category heading" .CatName}}Edit category {{beautifulName .}}{{end}}

+ {{if len .Hyphae | not}} +

{{block "empty cat" .}}This category is empty{{end}}

+ {{end}} + + {{if .GivenPermissionToModify}} +

{{block "add hypha" .}}Add a hypha to the category{{end}}

+
+ + + + +
+ + {{if len .Hyphae}} +

{{block "remove hyphae" .}}Remove hyphae from the category{{end}}

+
+ {{range .Hyphae}} + + +
+ {{end}} + + + +
+ {{end}} + {{end}} +
+{{end}} diff --git a/categories/view_page.html b/categories/view_page.html index e6bdf00..621d799 100644 --- a/categories/view_page.html +++ b/categories/view_page.html @@ -3,6 +3,11 @@ {{define "body"}} {{$catName := .CatName}}
+ {{if .GivenPermissionToModify}} +
+ {{block "edit" .}}Edit{{end}} +
+ {{end}}

{{block "cat" .}}Category{{end}} {{beautifulName $catName}}

{{if len .Hyphae | not}}

{{block "empty cat" .}}This category is empty{{end}}

diff --git a/categories/views.go b/categories/views.go index 67c1aac..cbfd035 100644 --- a/categories/views.go +++ b/categories/views.go @@ -24,14 +24,15 @@ const ruTranslation = ` var ( //go:embed *.html - fs embed.FS - viewListChain, viewPageChain, viewCardChain viewutil.Chain + fs embed.FS + viewListChain, viewPageChain, viewCardChain, viewEditChain viewutil.Chain ) func prepareViews() { viewCardChain = viewutil.CopyEnRuWith(fs, "view_card.html", ruTranslation) viewListChain = viewutil.CopyEnRuWith(fs, "view_list.html", ruTranslation) viewPageChain = viewutil.CopyEnRuWith(fs, "view_page.html", ruTranslation) + viewEditChain = viewutil.CopyEnRuWith(fs, "view_edit.html", ruTranslation) } type cardData struct { @@ -54,15 +55,26 @@ func CategoryCard(meta viewutil.Meta, hyphaName string) string { return buf.String() } -type pageData struct { +type catData struct { *viewutil.BaseData CatName string Hyphae []string GivenPermissionToModify bool } +func categoryEdit(meta viewutil.Meta, catName string) { + viewutil.ExecutePage(meta, viewEditChain, catData{ + BaseData: &viewutil.BaseData{ + Addr: "/edit-category/" + catName, + }, + CatName: catName, + Hyphae: hyphaeInCategory(catName), + GivenPermissionToModify: meta.U.CanProceed("add-to-category"), + }) +} + func categoryPage(meta viewutil.Meta, catName string) { - viewutil.ExecutePage(meta, viewPageChain, pageData{ + viewutil.ExecutePage(meta, viewPageChain, catData{ BaseData: &viewutil.BaseData{ Addr: "/category/" + catName, }, diff --git a/user/user.go b/user/user.go index 035badd..c827e34 100644 --- a/user/user.go +++ b/user/user.go @@ -35,8 +35,8 @@ var minimalRights = map[string]int{ "edit": 1, "upload-binary": 1, "upload-text": 1, - "add-to-category": 1, - "remove-from-category": 1, + "add-to-category": 2, + "remove-from-category": 2, "rename": 2, "remove-media": 2, "update-header-links": 3,