diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 277a2f5..c19d9d2 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -34,9 +34,11 @@ var ( ) func initServer(cfg core.Config) (err error) { - if err = godrop.PledgePromises("stdio rpath wpath cpath inet fattr flock proc exec id unveil"); err != nil { - return - } + // remove initial pledge due to violation with go1.12 + // sysctl kern.somaxconn + //if err = godrop.PledgePromises("stdio rpath wpath cpath inet fattr flock proc exec id unveil"); err != nil { + // return + //} dropCfg := godrop.Config{ User: cfg.User, Group: cfg.Group, diff --git a/pkg/core/helper.go b/pkg/core/helper.go new file mode 100644 index 0000000..948fb50 --- /dev/null +++ b/pkg/core/helper.go @@ -0,0 +1,11 @@ +package core + +// Contains checks if slice a contains string str +func Contains(str string, a []string) (int, bool) { + for i, s := range a { + if s == str { + return i, true + } + } + return -1, false +} diff --git a/pkg/core/permission.go b/pkg/core/permission.go index 726154a..01fd8cb 100644 --- a/pkg/core/permission.go +++ b/pkg/core/permission.go @@ -7,7 +7,6 @@ type Permission int const ( Invalid Permission = iota Public - Internal Private ) @@ -16,37 +15,27 @@ func ParsePermString(p string) Permission { case "1": return Public case "2": - return Internal - case "3": return Private } return Invalid } -func ReadPerm(username string, p *Page) bool { - switch p.Perm { +func ReadPerm(username string, p Permission, s Section) bool { + switch p { case Public: return true - case Internal: - return username != "" case Private: - return username == p.Owner + _, c := Contains(username, s.Members) + return c } return false } -func WritePerm(username, section string, p *Page) bool { - if section != WikiSection && section != username { - return false - } - switch p.Perm { - case Public, Internal: - if p.Owner == WikiSection { - return username != "" - } - return username == p.Owner - case Private: - return username == p.Owner +func WritePerm(username string, p Permission, s Section) bool { + switch p { + case Public, Private: + _, c := Contains(username, s.Members) + return c } return false } diff --git a/pkg/core/permission_test.go b/pkg/core/permission_test.go index be46dbd..40b205e 100644 --- a/pkg/core/permission_test.go +++ b/pkg/core/permission_test.go @@ -11,8 +11,7 @@ func TestParsePermString(t *testing.T) { data := map[string]Permission{ "": Invalid, "1": Public, - "2": Internal, - "3": Private, + "2": Private, "123": Invalid, "test": Invalid, } @@ -28,21 +27,23 @@ func TestParsePermString(t *testing.T) { func TestReadPerm(t *testing.T) { data := []struct { Username string - Page *Page + Perm Permission + Section Section OK bool }{ - {"", &Page{Perm: Invalid, Owner: "admin"}, false}, - {"", &Page{Perm: Public, Owner: "admin"}, true}, - {"user", &Page{Perm: Public, Owner: "admin"}, true}, - {"", &Page{Perm: Internal, Owner: "admin"}, false}, - {"user", &Page{Perm: Internal, Owner: "admin"}, true}, - {"", &Page{Perm: Private, Owner: "admin"}, false}, - {"user", &Page{Perm: Private, Owner: "admin"}, false}, - {"admin", &Page{Perm: Private, Owner: "admin"}, true}, + {"", Invalid, Section{Members: []string{"admin"}}, false}, + {"", Public, Section{Members: []string{"admin"}}, true}, + {"user", Public, Section{Members: []string{"admin"}}, true}, + {"", Private, Section{Members: []string{"admin"}}, false}, + {"user", Private, Section{Members: []string{"admin"}}, false}, + {"", Private, Section{Members: []string{"user"}}, false}, + {"user", Private, Section{Members: []string{"user"}}, true}, + {"user", Private, Section{Members: []string{"user", "admin"}}, true}, + {"admin", Private, Section{Members: []string{"user"}}, false}, } for i, v := range data { t.Run(fmt.Sprintf("Read:%d", i), func(t *testing.T) { - if ReadPerm(v.Username, v.Page) != v.OK { + if ReadPerm(v.Username, v.Perm, v.Section) != v.OK { t.Fail() } }) @@ -52,28 +53,23 @@ func TestReadPerm(t *testing.T) { func TestWritePerm(t *testing.T) { data := []struct { Username string - Section string - Page *Page + Perm Permission + Section Section OK bool }{ - {"user", "admin", &Page{Perm: Invalid, Owner: "admin"}, false}, - {"", "user", &Page{Perm: Invalid, Owner: "admin"}, false}, - {"user", "user", &Page{Perm: Invalid, Owner: "user"}, false}, - {"user", "user", &Page{Perm: Public, Owner: "user"}, true}, - {"user", "user", &Page{Perm: Internal, Owner: "user"}, true}, - {"user", "user", &Page{Perm: Private, Owner: "user"}, true}, - {"", WikiSection, &Page{Perm: Invalid, Owner: "admin"}, false}, - {"", WikiSection, &Page{Perm: Public, Owner: "admin"}, false}, - {"", WikiSection, &Page{Perm: Internal, Owner: "admin"}, false}, - {"user", WikiSection, &Page{Perm: Public, Owner: WikiSection}, true}, - {"user", WikiSection, &Page{Perm: Internal, Owner: WikiSection}, true}, - {"", "admin", &Page{Perm: Private, Owner: "admin"}, false}, - {"user", "admin", &Page{Perm: Private, Owner: "admin"}, false}, - {"admin", "admin", &Page{Perm: Private, Owner: "admin"}, true}, + {"", Invalid, Section{Members: []string{"user"}}, false}, + {"", Public, Section{Members: []string{"user"}}, false}, + {"user", Public, Section{Members: []string{"user"}}, true}, + {"user", Public, Section{Members: []string{"admin"}}, false}, + {"user", Private, Section{Members: []string{"user"}}, true}, + {"", Private, Section{Members: []string{"user"}}, false}, + {"", Private, Section{Members: []string{"user", "admin"}}, false}, + {"user", Private, Section{Members: []string{"user", "admin"}}, true}, + {"admin", Private, Section{Members: []string{"user", "admin"}}, true}, } for i, v := range data { t.Run(fmt.Sprintf("Write:%d", i), func(t *testing.T) { - if WritePerm(v.Username, v.Section, v.Page) != v.OK { + if WritePerm(v.Username, v.Perm, v.Section) != v.OK { t.Fail() } }) diff --git a/pkg/core/types.go b/pkg/core/types.go index 6d85ae8..183039f 100644 --- a/pkg/core/types.go +++ b/pkg/core/types.go @@ -12,7 +12,6 @@ type Page struct { HTML template.HTML `json:"html"` Created string `json:"created"` Updated string `json:"updated"` - Owner string `json:"owner"` Perm Permission `json:"perm"` } @@ -29,15 +28,27 @@ func (p UpdatedPages) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p UpdatedPages) Less(i, j int) bool { return p[i].Updated > p[j].Updated } type Section struct { - Section string - Pages UpdatedPages + Name string + User bool + Members []string } type Sections []Section func (s Sections) Len() int { return len(s) } func (s Sections) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s Sections) Less(i, j int) bool { return s[i].Section < s[j].Section } +func (s Sections) Less(i, j int) bool { return s[i].Name < s[j].Name } + +type SectionPage struct { + Section string + Pages UpdatedPages +} + +type SectionPages []SectionPage + +func (s SectionPages) Len() int { return len(s) } +func (s SectionPages) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s SectionPages) Less(i, j int) bool { return s[i].Section < s[j].Section } type User struct { Username string diff --git a/pkg/db/db.go b/pkg/db/db.go index a07164c..6bae139 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -57,9 +57,18 @@ func New(cfg core.Config) (db *DB, err error) { if err != nil { return } + if db.SectionExists(core.WikiSection) != nil { + err = db.CreateSection(core.WikiSection, []string{defUser}, false) + if err != nil { + return + } + } _, err = db.CreatePage(core.IndexPage, core.WikiSection, welcome, defUser, core.Public) - return + if err != nil { + return + } + return db.RunMigrations() } func (db *DB) Dump(w io.Writer) error { diff --git a/pkg/db/helper.go b/pkg/db/helper.go index 46ca6f9..3772ca0 100644 --- a/pkg/db/helper.go +++ b/pkg/db/helper.go @@ -4,10 +4,11 @@ package db import ( "crypto/sha256" + "git.giftfish.de/ston1th/gowiki/pkg/core" "time" ) -var reservedUsers = []string{ +var reservedNames = []string{ "blacklist", "login", "logout", @@ -27,13 +28,18 @@ func hasTrimPrefix(s, prefix string) (string, bool) { return s, false } -func reservedUser(username string) bool { - for _, v := range reservedUsers { - if username == v { - return true - } +func addOrRemove(s string, a []string) []string { + i, _ := core.Contains(s, a) + switch i { + case -1: + return append(a, s) + case 0: + return a[1:] + case len(a): + return a[:i] + default: + return append(a[:i], a[i+1:]...) } - return false } func validatePassword(pw string) (b []byte) { diff --git a/pkg/db/migration.go b/pkg/db/migration.go new file mode 100644 index 0000000..1408bdd --- /dev/null +++ b/pkg/db/migration.go @@ -0,0 +1,72 @@ +package db + +import ( + "git.giftfish.de/ston1th/gowiki/pkg/core" + "git.giftfish.de/ston1th/gowiki/pkg/log" +) + +const ( + versionKey = "version/version" + currentVersion = 2 +) + +type migrator func(*DB) (int, error) + +var migrators = []migrator{ + func(db *DB) (int, error) { + return 0, nil + }, + func(db *DB) (version int, err error) { + version = 1 + return + }, + func(db *DB) (version int, err error) { + version = 2 + // recreate all pages with new format + var pages []string + db.store.ForEach(func(k string, _ []byte) error { + if trim, ok := hasTrimPrefix(k, pagePrefix); ok { + pages = append(pages, trim) + } + return nil + }) + var p core.Page + for _, v := range pages { + k := pagePrefix + v + err := db.store.Get(k, &p) + if err != nil { + log.Printf("db: migrator[%d]: pageGet %s: %s", version, k, err) + continue + } + err = db.store.Set(k, &p) + if err != nil { + log.Printf("db: migrator[%d]: pageSet %s: %s", version, k, err) + continue + } + } + return + }, +} + +func (db *DB) RunMigrations() (err error) { + var version int + err = db.store.Get(versionKey, &version) + if err == ErrKeyNotFound { + err = db.store.Set(versionKey, 0) + if err != nil { + return + } + } + log.Printf("db: detected database version %d", version) + for version < currentVersion { + log.Printf("db: running migration %d", version) + version, err = migrators[version](db) + if err != nil { + return + } + err = db.store.Set(versionKey, version) + if err != nil { + return + } + } +} diff --git a/pkg/db/page.go b/pkg/db/page.go index 3078b3a..1f0f163 100644 --- a/pkg/db/page.go +++ b/pkg/db/page.go @@ -14,15 +14,14 @@ import ( const pagePrefix = "page/" var ( - errPageNotFound = store.ErrKeyNotFound - errPermissionDenied = errors.New("db: permission denied") - errInvalidPermission = errors.New("db: invalid permission") - errPrivateWikiPage = errors.New("db: private wiki pages are not allowed") - errNonPublicIndexPage = errors.New("db: internal/private index page is not allowed") - errDeleteIndexPage = errors.New("db: index page can not be deleted") + errPageNotFound = store.ErrKeyNotFound + errPermissionDenied = errors.New("db: permission denied") + errInvalidPermission = errors.New("db: invalid permission") + errPrivateWikiPage = errors.New("db: private wiki pages are not allowed") + errDeleteIndexPage = errors.New("db: index page can not be deleted") ) -func (db *DB) GetAllSections(username string) (sections core.Sections) { +func (db *DB) GetAllSections(username string) (sections core.SectionPages) { m := make(map[string]core.UpdatedPages) db.store.ForEach(func(k string, _ []byte) error { if trim, ok := hasTrimPrefix(k, pagePrefix); ok { @@ -46,7 +45,7 @@ func (db *DB) GetAllSections(username string) (sections core.Sections) { if l > 5 { l = 5 } - sections = append(sections, core.Section{s, p[:l]}) + sections = append(sections, core.SectionPage{s, p[:l]}) } sort.Sort(sections) return @@ -86,7 +85,7 @@ func (db *DB) ValidatePage(st, username string) bool { db.cache.Add(st, p) return true } - return core.ReadPerm(username, p) + return db.ReadPerm(st, username, p.Perm) } func (db *DB) GetPage(section, title, username string) (p *core.Page, err error) { @@ -97,7 +96,7 @@ func (db *DB) GetPage(section, title, username string) (p *core.Page, err error) db.cache.Add(st, p) return } - if !core.ReadPerm(username, p) { + if !db.ReadPerm(section, username, p.Perm) { err = errPageNotFound } return @@ -109,7 +108,7 @@ func (db *DB) getPage(title, username string) (p *core.Page, err error) { if err != nil { return } - if !core.ReadPerm(username, p) { + if !db.ReadPerm(title, username, p.Perm) { err = errPageNotFound } return @@ -120,13 +119,9 @@ func (db *DB) CreatePage(title, section, markdown, username string, p core.Permi err = errInvalidPermission return } - owner := username - if section == core.WikiSection { - owner = core.WikiSection - if p == core.Private { - err = errPrivateWikiPage - return - } + if section == core.WikiSection && p == core.Private { + err = errPrivateWikiPage + return } st := render.StoreTitle(section, render.Title(title)) _, err = db.getPage(st, username) @@ -139,7 +134,6 @@ func (db *DB) CreatePage(title, section, markdown, username string, p core.Permi StoreTitle: st, Markdown: markdown, Created: created(username), - Owner: owner, Perm: p, } search := render.Render(page) @@ -166,17 +160,12 @@ func (db *DB) UpdatePage(title, section, markdown, username string, p core.Permi err = errPrivateWikiPage return } - if section == core.WikiSection && title == core.IndexPage && - (p == core.Internal || p == core.Private) { - err = errNonPublicIndexPage - return - } st := render.StoreTitle(section, title) page, err := db.getPage(st, username) if err != nil { return } - if !core.WritePerm(username, section, page) { + if !db.WritePerm(title, username, page.Perm) { return errPermissionDenied } @@ -216,7 +205,7 @@ func (db *DB) DeletePage(title, section, username string) (err error) { if page, err = db.getPage(st, username); err != nil { return } - if !core.WritePerm(username, section, page) { + if !db.WritePerm(section, username, page.Perm) { return errPermissionDenied } return db.deletePage(st) diff --git a/pkg/db/permission.go b/pkg/db/permission.go new file mode 100644 index 0000000..4d806f3 --- /dev/null +++ b/pkg/db/permission.go @@ -0,0 +1,26 @@ +// Copyright (C) 2019 Marius Schellenberger + +package db + +import ( + "git.giftfish.de/ston1th/gowiki/pkg/core" + "git.giftfish.de/ston1th/gowiki/pkg/render" +) + +func (db *DB) ReadPerm(st, username string, p core.Permission) bool { + section, _ := render.SplitStoreTitle(st) + s, err := db.GetSection(section) + if err != nil { + return false + } + return core.ReadPerm(username, p, s) +} + +func (db *DB) WritePerm(st, username string, p core.Permission) bool { + section, _ := render.SplitStoreTitle(st) + s, err := db.GetSection(section) + if err != nil { + return false + } + return core.WritePerm(username, p, s) +} diff --git a/pkg/db/section.go b/pkg/db/section.go new file mode 100644 index 0000000..0f88086 --- /dev/null +++ b/pkg/db/section.go @@ -0,0 +1,103 @@ +// Copyright (C) 2019 Marius Schellenberger + +package db + +import ( + "errors" + "git.giftfish.de/ston1th/gowiki/pkg/core" + "git.giftfish.de/ston1th/gowiki/pkg/log" + "sort" + "strings" +) + +const sectionPrefix = "section/" + +var ( + errSectionExists = errors.New("db: section already exist") +) + +func (db *DB) GetSections() (secs core.Sections, err error) { + err = db.store.ForEach(func(k string, _ []byte) error { + if trim, ok := hasTrimPrefix(k, sectionPrefix); ok { + s, err := db.GetSection(trim) + if err == nil { + secs = append(secs, s) + } + } + return nil + }) + sort.Sort(secs) + return +} + +func (db *DB) GetSection(section string) (s core.Section, err error) { + err = db.store.Get(sectionPrefix+section, &s) + return +} + +func (db *DB) SectionExists(section string) error { + return db.store.Get(sectionPrefix+section, nil) +} + +func (db *DB) CreateSection(section string, members []string, user bool) error { + section = userRe.ReplaceAllString(section, "") + if err := db.SectionExists(section); err == nil { + return errSectionExists + } + return db.UpdateSection(section, members, user) +} + +func (db *DB) UpdateSection(section string, members []string, user bool) error { + section = userRe.ReplaceAllString(section, "") + if _, ok := core.Contains(section, reservedNames); ok { + return errNameReserved + } + var m []string + if user { + m = append(m, section) + } else { + for _, v := range members { + if v == "" { + continue + } + if err := db.UserExists(v); err == nil { + m = append(m, v) + } + } + } + return db.store.Set(sectionPrefix+section, &core.Section{section, user, m}) +} + +func (db *DB) DeleteSection(section string, user bool) error { + if section == core.WikiSection { + return errors.New("section '" + core.WikiSection + "' cannot be deleted") + } + s, err := db.GetSection(section) + if err != nil { + return err + } + err = db.store.Delete(sectionPrefix + section) + if err != nil { + return err + } + if !s.User && !user { + return nil + } + section += "/" + var pages []string + db.store.ForEach(func(k string, _ []byte) error { + if trim, ok := hasTrimPrefix(k, pagePrefix); ok { + if strings.HasPrefix(trim, section) { + pages = append(pages, trim) + } + } + return nil + }) + for _, p := range pages { + err := db.deletePage(p) + if err != nil { + log.Debugf("DeleteSection %s, %s", section, err) + } + } + return nil +} diff --git a/pkg/db/user.go b/pkg/db/user.go index e283aad..05a922b 100644 --- a/pkg/db/user.go +++ b/pkg/db/user.go @@ -5,14 +5,12 @@ package db import ( "errors" "git.giftfish.de/ston1th/gowiki/pkg/core" - "git.giftfish.de/ston1th/gowiki/pkg/log" "git.giftfish.de/ston1th/gowiki/pkg/otp" "git.giftfish.de/ston1th/jwt/v3" "golang.org/x/crypto/bcrypt" "regexp" "sort" "strconv" - "strings" ) const userPrefix = "user/" @@ -20,7 +18,7 @@ const userPrefix = "user/" var ( errUserNotFound = errors.New("db: user not found") errUserExists = errors.New("db: user already exist") - errUserReserved = errors.New("db: username is reserved") + errNameReserved = errors.New("db: name is reserved") userRe = regexp.MustCompile("[^a-zA-Z0-9]+") ) @@ -64,8 +62,8 @@ func (db *DB) UserExists(username string) error { func (db *DB) CreateUser(username, password string, admin bool) error { username = userRe.ReplaceAllString(username, "") - if reservedUser(username) { - return errUserReserved + if _, ok := core.Contains(username, reservedNames); ok { + return errNameReserved } if err := db.UserExists(username); err == nil { return errUserExists @@ -74,6 +72,10 @@ func (db *DB) CreateUser(username, password string, admin bool) error { if err != nil { return err } + err = db.CreateSection(username, nil, true) + if err != nil { + return err + } return db.store.Set(userPrefix+username, &core.User{ Username: username, Password: string(hash), @@ -218,21 +220,5 @@ func (db *DB) DeleteUser(username string) error { if err != nil { return err } - username += "/" - var pages []string - db.store.ForEach(func(k string, _ []byte) error { - if trim, ok := hasTrimPrefix(k, pagePrefix); ok { - if strings.HasPrefix(trim, username) { - pages = append(pages, trim) - } - } - return nil - }) - for _, p := range pages { - err := db.deletePage(p) - if err != nil { - log.Debugf("DeleteUser %s, %s", username, err) - } - } - return nil + return db.DeleteSection(username, true) } diff --git a/pkg/render/render.go b/pkg/render/render.go index 1c28e08..4366eba 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -47,8 +47,8 @@ func StoreTitle(section, title string) string { return section + "/" + title } -func UnstoreTitle(storeTitle string) (section, title string) { - if a := strings.Split(storeTitle, "/"); len(a) == 2 { +func SplitStoreTitle(st string) (section, title string) { + if a := strings.Split(st, "/"); len(a) == 2 { return a[0], a[1] } return diff --git a/pkg/render/render_test.go b/pkg/render/render_test.go index 60d6f52..7fb5971 100644 --- a/pkg/render/render_test.go +++ b/pkg/render/render_test.go @@ -15,8 +15,8 @@ func TestTitleFunctions(t *testing.T) { t.Fail() } }) - t.Run("UnstoreTitle", func(t *testing.T) { - se, ti := UnstoreTitle(combined) + t.Run("SplitStoreTitle", func(t *testing.T) { + se, ti := SplitStoreTitle(combined) if se != section || ti != title { t.Fail() } diff --git a/pkg/server/handler.go b/pkg/server/handler.go index b509852..f89f7bf 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -236,6 +236,57 @@ func sectionHandler(ctx *Context) { ctx.Exec() } +func sectionNewHandler(ctx *Context) { + ctx.Template("sectionNewHandler") + section := ctx.Var("section") + ctx.Data = webData{ + Title: section, + BodyTitle: section, + Admin: ctx.Admin(), + } + var err error + ctx.Data.Data, err = ctx.Srv.DB.GetAllSectionPages(section, ctx.User()) + if err != nil { + ctx.NotFound() + return + } + ctx.Exec() +} + +func sectionDelHandler(ctx *Context) { + ctx.Template("sectionDelHandler") + section := ctx.Var("section") + ctx.Data = webData{ + Title: section, + BodyTitle: section, + Admin: ctx.Admin(), + } + var err error + ctx.Data.Data, err = ctx.Srv.DB.GetAllSectionPages(section, ctx.User()) + if err != nil { + ctx.NotFound() + return + } + ctx.Exec() +} + +func sectionEditHandler(ctx *Context) { + ctx.Template("sectionEditHandler") + section := ctx.Var("section") + ctx.Data = webData{ + Title: section, + BodyTitle: section, + Admin: ctx.Admin(), + } + var err error + ctx.Data.Data, err = ctx.Srv.DB.GetAllSectionPages(section, ctx.User()) + if err != nil { + ctx.NotFound() + return + } + ctx.Exec() +} + func pageNewHandler(ctx *Context) { ctx.Template("pageNewHandler") ctx.Data = webData{Title: "New Page"} diff --git a/pkg/server/routes.go b/pkg/server/routes.go index 563c351..ac753ef 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -34,6 +34,24 @@ var routes = []route{ sectionsHandler, []string{"GET"}, }, + { + "/sections/new", + adminAuthHandler( + sectionNewHandler), + []string{"GET", "POST"}, + }, + { + "/section/del/{section:[a-zA-Z0-9]+$}", + adminAuthHandler( + sectionDelHandler), + []string{"GET", "POST"}, + }, + { + "/section/edit/{section:[a-zA-Z0-9]+$}", + adminAuthHandler( + sectionEditHandler), + []string{"GET", "POST"}, + }, { "/search", searchHandler, diff --git a/pkg/server/templates.go b/pkg/server/templates.go index 4e3b71c..45fcf56 100644 --- a/pkg/server/templates.go +++ b/pkg/server/templates.go @@ -459,6 +459,92 @@ const ( {{end}} +{{end}}` + sectionDel = `{{define "body"}} +{{if .Data}} + +{{end}} +{{end}}` + sectionEdit = `{{define "body"}} +{{if .Data}} +
+
+
+
+ {{.BodyTitle}} + {{if .Data.Secret}} + Disable TOTP + {{else}} + Enable TOTP + {{end}} +
+
+
+ +
+ + +
+
+ + +
+
+ + +
+ {{if .Admin}} +
+ + {{if .Data.Admin}} + + {{else}} + + {{end}} +
+ {{end}} + + {{if .Admin}} + Back + {{else}} + Back + {{end}} + Delete +
+ {{if .Admin}} + {{if eq .Data.Locked 3}} +
+ +
+ + +
+
+ {{end}} + {{end}} +
+
+
+
+{{end}} {{end}}` section = `{{define "body"}} {{end}} +{{end}}` + sectionNew = `{{define "body"}} +
+
+
+
+ {{.BodyTitle}} +
+
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Back +
+
+
+
+
{{end}}` sections = `{{define "body"}} +{{if .Admin}} +
+
+ New Section +
+
+{{end}} {{if .Data}}
{{range $index, $item := .Data}} diff --git a/templates/userDel.html b/templates/userDel.html index da9d231..234b6a9 100644 --- a/templates/userDel.html +++ b/templates/userDel.html @@ -8,7 +8,7 @@ Delete {{.Data.Username}}?
-

You are about to delete user {{.Data.Username}}.
This will also remove all private pages of this user.

+

You are about to delete user {{.Data.Username}}.
This will also remove all pages of this user.