From b3b62af3a443367dcac825bbc69fe420358a8752 Mon Sep 17 00:00:00 2001 From: ston1th Date: Tue, 20 Aug 2019 23:57:43 +0200 Subject: [PATCH] unstable: initial tags --- pkg/core/const.go | 4 ++ pkg/core/types.go | 13 ++++-- pkg/db/db.go | 9 +++- pkg/db/helper.go | 7 ++- pkg/db/index.go | 25 ++++++++--- pkg/db/migration.go | 21 ++++++--- pkg/db/tags.go | 69 +++++++++++++++++++++++++++++ pkg/db/user.go | 5 +-- pkg/fs/helper.go | 3 ++ pkg/index/classify.go | 32 -------------- pkg/index/index.go | 15 +++---- pkg/server/handler.go | 98 ++++++++++++++++++++++++++++++++++++++++- pkg/server/routes.go | 23 +++++++++- pkg/server/templates.go | 92 +++++++++++++++++++++++++++++++++++++- pkg/store/boltstore.go | 9 ++++ pkg/store/gob.go | 25 +++++++++++ pkg/store/helper.go | 11 +++++ pkg/store/marshal.go | 22 --------- pkg/store/store.go | 1 + pkg/tags/tags.go | 18 ++++++++ templates.sh | 4 ++ templates/custom.css | 2 +- templates/file.html | 1 + templates/index.html | 2 +- templates/menu.html | 3 ++ templates/tagsDel.html | 26 +++++++++++ templates/tagsEdit.html | 26 +++++++++++ templates/tagsList.html | 28 ++++++++++++ 28 files changed, 503 insertions(+), 91 deletions(-) create mode 100644 pkg/db/tags.go delete mode 100644 pkg/index/classify.go create mode 100644 pkg/store/gob.go create mode 100644 pkg/store/helper.go create mode 100644 pkg/tags/tags.go create mode 100644 templates/tagsDel.html create mode 100644 templates/tagsEdit.html create mode 100644 templates/tagsList.html diff --git a/pkg/core/const.go b/pkg/core/const.go index ecb7dbb..8ae9fa2 100644 --- a/pkg/core/const.go +++ b/pkg/core/const.go @@ -7,12 +7,16 @@ const ( TotpURI = "/totp" LoginURI = "/login" LogoutURI = "/logout" + SearchURI = "/search" + TagsURI = "/tags" + UserURI = "/user" RawPrefix = "/raw" IndexPrefix = "/index" UploadPrefix = "/upload" NewPrefix = "/new" MovePrefix = "/move" + TagsPrefix = "/tags" DeletePrefix = "/delete" Favicon = "/favicon.ico" diff --git a/pkg/core/types.go b/pkg/core/types.go index 488d740..d05e5b7 100644 --- a/pkg/core/types.go +++ b/pkg/core/types.go @@ -12,14 +12,19 @@ type User struct { } type Result struct { - ID string - Path string - Keyword string - HTML template.HTML + ID string + Path string + Tags string + HTML template.HTML } type Results []Result +type Tag struct { + Name string + Regex string +} + type Path struct { Name string Abs string diff --git a/pkg/db/db.go b/pkg/db/db.go index 6268ddf..8966941 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -37,7 +37,14 @@ func New(cfg core.Config) (db *DB, err error) { if err != nil && err != store.ErrKeyNotFound { return } - err = db.RunMigrations() + err = db.store.Get(versionKey, nil) + if err == store.ErrKeyNotFound { + err = db.addDefaultTags() + if err != nil { + return + } + } + err = db.runMigrations() return } diff --git a/pkg/db/helper.go b/pkg/db/helper.go index 3176685..18a74ca 100644 --- a/pkg/db/helper.go +++ b/pkg/db/helper.go @@ -2,7 +2,12 @@ package db -import "crypto/sha256" +import ( + "crypto/sha256" + "regexp" +) + +var nameRe = regexp.MustCompile("[^a-zA-Z0-9]+") // Parts taken from strings.TrimPrefix func hasTrimPrefix(s, prefix string) (string, bool) { diff --git a/pkg/db/index.go b/pkg/db/index.go index 5b2955c..7f8eb69 100644 --- a/pkg/db/index.go +++ b/pkg/db/index.go @@ -49,24 +49,35 @@ func (db *DB) DeleteID(path string) error { return db.store.Delete(idPrefix + path) } -func (db *DB) NewFile(id, path string) (err error) { +func (db *DB) NewFile(id, path string, tags []string) (err error) { err = db.store.Set(idPrefix+path, id) if err != nil { return } err = db.store.Set(pathPrefix+id, path) - return + if err != nil { + return + } + return db.SetTag(path, tags) } -func (db *DB) MoveFile(op, np string) error { +func (db *DB) MoveFile(op, np string) (err error) { if !db.IsIndexed(op) { return nil } id, err := db.DeleteFile(op) if err != nil { - return err + return } - return db.NewFile(id, np) + tags, err := db.GetTag(op) + if err != nil { + return + } + err = db.NewFile(id, np, tags) + if err != nil { + return + } + return db.UnsetTag(op) } func (db *DB) DeleteFile(path string) (id string, err error) { @@ -81,6 +92,10 @@ func (db *DB) DeleteFile(path string) (id string, err error) { if err != nil { return } + err = db.UnsetTag(path) + if err != nil { + return + } err = db.DeletePath(id) return } diff --git a/pkg/db/migration.go b/pkg/db/migration.go index a989548..4dfa638 100644 --- a/pkg/db/migration.go +++ b/pkg/db/migration.go @@ -9,18 +9,25 @@ import ( const ( versionKey = "version/version" - currentVersion = 1 + currentVersion = 2 ) -type migrator func(*DB) (int, error) +type migrator func(*DB) error var migrators = []migrator{ - func(db *DB) (int, error) { - return 0, nil + func(db *DB) error { + return nil + }, + func(db *DB) error { + // dummy placeholder + return nil + }, + func(db *DB) error { + return db.addDefaultTags() }, } -func (db *DB) RunMigrations() (err error) { +func (db *DB) runMigrations() (err error) { var version int err = db.store.Get(versionKey, &version) if err == store.ErrKeyNotFound { @@ -37,11 +44,11 @@ func (db *DB) RunMigrations() (err error) { for version < currentVersion { v := version + 1 log.Printf("db: running migration %d", v) - version, err = migrators[v](db) + err = migrators[v](db) if err != nil { return } - err = db.store.Set(versionKey, version) + err = db.store.Set(versionKey, v) if err != nil { return } diff --git a/pkg/db/tags.go b/pkg/db/tags.go new file mode 100644 index 0000000..162ba48 --- /dev/null +++ b/pkg/db/tags.go @@ -0,0 +1,69 @@ +// Copyright (C) 2019 Marius Schellenberger + +package db + +import ( + "git.giftfish.de/ston1th/docstore/pkg/core" + "regexp" +) + +const ( + tagsPrefix = "tags/" + tagPrefix = "tag/" +) + +var defaultTags = []core.Tag{ + {"invoice", `(?i)[^e]rechnung|quittung|beleg|invoice|bill|check`}, + {"tax", `(?i)steuer|lohn|tax|salary`}, + {"contract", `(?i)vertrag|kündigung|vereinbarung|contract|termination|agreement`}, + {"insurance", `(?i)versicherung|versichert|insurance|insured`}, +} + +func (db *DB) addDefaultTags() (err error) { + for _, t := range defaultTags { + err = db.NewTag(t.Name, t.Regex) + if err != nil { + return + } + } + return +} + +func (db *DB) GetAllTags() (tags []core.Tag, err error) { + err = db.store.ForEachPrefix(tagsPrefix, func(k string, _ []byte) error { + var t core.Tag + err := db.store.Get(tagsPrefix+k, &t) + if err == nil { + tags = append(tags, t) + } + return nil + }) + return +} + +func (db *DB) DeleteTag(name string) error { + return db.store.Delete(tagsPrefix + name) +} + +func (db *DB) NewTag(name, regex string) (err error) { + _, err = regexp.Compile(regex) + if err != nil { + return + } + name = nameRe.ReplaceAllString(name, "") + err = db.store.Set(tagsPrefix+name, core.Tag{name, regex}) + return +} + +func (db *DB) GetTag(path string) (tags []string, err error) { + err = db.store.Get(tagPrefix+path, &tags) + return +} + +func (db *DB) SetTag(path string, tags []string) error { + return db.store.Set(tagPrefix+path, tags) +} + +func (db *DB) UnsetTag(path string) error { + return db.store.Delete(tagPrefix + path) +} diff --git a/pkg/db/user.go b/pkg/db/user.go index 6c3d225..57b3258 100644 --- a/pkg/db/user.go +++ b/pkg/db/user.go @@ -7,7 +7,6 @@ import ( "git.giftfish.de/ston1th/docstore/pkg/core" "git.giftfish.de/ston1th/docstore/pkg/otp" "golang.org/x/crypto/bcrypt" - "regexp" "strings" ) @@ -20,8 +19,6 @@ var ( errWrongLogin = errors.New("db: wrong login") errLocked = errors.New("db: user locked") errUserExists = errors.New("db: user already exist") - - userRe = regexp.MustCompile("[^a-zA-Z0-9]+") ) func (db *DB) UserExists() (b bool) { @@ -53,7 +50,7 @@ func (db *DB) GetUser() (u core.User, err error) { } func (db *DB) CreateUser(username, password string) error { - username = userRe.ReplaceAllString(username, "") + username = nameRe.ReplaceAllString(username, "") if db.UserExists() { return errUserExists } diff --git a/pkg/fs/helper.go b/pkg/fs/helper.go index 54c6f50..b7b153f 100644 --- a/pkg/fs/helper.go +++ b/pkg/fs/helper.go @@ -24,6 +24,9 @@ var reserved = []string{ core.TotpURI, core.LoginURI, core.LogoutURI, + core.SearchURI, + core.TagsURI, + core.UserURI, core.RawPrefix, core.IndexPrefix, core.UploadPrefix, diff --git a/pkg/index/classify.go b/pkg/index/classify.go deleted file mode 100644 index 9e08047..0000000 --- a/pkg/index/classify.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2019 Marius Schellenberger - -package index - -import ( - "regexp" -) - -var classes = []class{ - {regexp.MustCompile(`(?i)[^e]rechnung|quittung|beleg|invoice|bill|check`), []string{"invoice", "rechnung"}}, - {regexp.MustCompile(`(?i)steuer|lohn|tax|salary`), []string{"tax", "steuer"}}, - {regexp.MustCompile(`(?i)vertrag|kündigung|vereinbarung|contract|termination|agreement`), []string{"contract", "vertrag"}}, - {regexp.MustCompile(`(?i)versicherung|versichert|insurance|insured`), []string{"insurance", "versicherung"}}, -} - -type class struct { - r *regexp.Regexp - k []string -} - -func classify(text string) (keyword []string) { - keyword = []string{"", ""} - n := 0 - for _, v := range classes { - num := len(v.r.FindAllString(text, -1)) - if num > n && num >= 2 { - keyword = v.k - n = num - } - } - return -} diff --git a/pkg/index/index.go b/pkg/index/index.go index d8364fd..97f6381 100644 --- a/pkg/index/index.go +++ b/pkg/index/index.go @@ -19,7 +19,7 @@ const docType = "document" type document struct { Text string `json:"text"` - Keyword []string `json:"keyword"` + Tags []string `json:"tags"` Created time.Time `json:"created"` } @@ -61,7 +61,7 @@ func (i *Index) Close() error { return i.i.Close() } -func (i *Index) Add(text string) (id string, err error) { +func (i *Index) Add(text string, tags []string) (id string, err error) { id = newID() for { doc, _ := i.i.Document(id) @@ -70,8 +70,7 @@ func (i *Index) Add(text string) (id string, err error) { } id = newID() } - k := classify(text) - err = i.i.Index(id, &document{text, k, time.Now()}) + err = i.i.Index(id, &document{text, tags, time.Now()}) return } @@ -97,12 +96,12 @@ func (i *Index) Search(search string) (results core.Results, err error) { continue } for fragField, frags := range hit.Fragments { - if fragField == "keyword" { - var k string + if fragField == "tags" { + var t string for _, f := range frags { - k += f + t += f } - r.Keyword = strings.ReplaceAll(strings.ReplaceAll(k, "", ""), "", "") + r.Tags = strings.ReplaceAll(strings.ReplaceAll(t, "", ""), "", "") } if fragField == "text" || fragField == "created" { for _, f := range frags { diff --git a/pkg/server/handler.go b/pkg/server/handler.go index 1b34280..b43de37 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -7,6 +7,7 @@ import ( "git.giftfish.de/ston1th/docstore/pkg/fs" "git.giftfish.de/ston1th/docstore/pkg/log" "git.giftfish.de/ston1th/docstore/pkg/otp" + "git.giftfish.de/ston1th/docstore/pkg/tags" "git.giftfish.de/ston1th/jwt/v3" "html/template" "net/http" @@ -197,12 +198,17 @@ func indexHandler(ctx *Context) { log.Printf("scanner: %s: %s", path, err) return } - id, err := ctx.Srv.DB.Index.Add(txt) + t, err := ctx.Srv.DB.GetAllTags() + if err != nil { + log.Printf("getTags: %s: %s", path, err) + } + found := tags.Find(txt, t) + id, err := ctx.Srv.DB.Index.Add(txt, found) if err != nil { log.Printf("index: %s: %s", path, err) return } - err = ctx.Srv.DB.NewFile(id, file) + err = ctx.Srv.DB.NewFile(id, file, found) if err != nil { log.Printf("newFile: %s: %s", path, err) } @@ -687,6 +693,94 @@ func userTotpHandler(ctx *Context) { } } +func tagsHandler(ctx *Context) { + ctx.Template("tagsHandler") + ctx.Data = webData{ + Title: "Tags", + BodyTitle: "Tags", + } + t, err := ctx.Srv.DB.GetAllTags() + if err != nil { + ctx.Error(err) + return + } + ctx.Data.Data = t + switch ctx.Method() { + case "GET": + ctx.Exec() + } +} + +func tagsEditHandler(ctx *Context) { + ctx.Template("tagsEditHandler") + ctx.Data = webData{ + Title: "Edit User", + BodyTitle: "Edit User", + } + u, err := ctx.Srv.DB.GetUserWithoutPassword() + if err != nil { + ctx.Error(err) + return + } + ctx.Data.Data = u + switch ctx.Method() { + case "GET": + ctx.Exec() + case "POST": + if !ctx.CheckXsrf() { + return + } + password := ctx.Form("password") + repeat := ctx.Form("repeat") + + if password != repeat { + ctx.Error("passwords do not match") + return + } + if err := ctx.Srv.DB.UpdateUserPassword(password); err != nil { + ctx.Error(err) + return + } + log.Printf("update: %s updated\n", ctx.User()) + ctx.Redirect(core.IndexURI, http.StatusFound) + } +} + +func tagsDelHandler(ctx *Context) { + ctx.Template("tagsDelHandler") + ctx.Data = webData{ + Title: "Edit User", + BodyTitle: "Edit User", + } + u, err := ctx.Srv.DB.GetUserWithoutPassword() + if err != nil { + ctx.Error(err) + return + } + ctx.Data.Data = u + switch ctx.Method() { + case "GET": + ctx.Exec() + case "POST": + if !ctx.CheckXsrf() { + return + } + password := ctx.Form("password") + repeat := ctx.Form("repeat") + + if password != repeat { + ctx.Error("passwords do not match") + return + } + if err := ctx.Srv.DB.UpdateUserPassword(password); err != nil { + ctx.Error(err) + return + } + log.Printf("update: %s updated\n", ctx.User()) + ctx.Redirect(core.IndexURI, http.StatusFound) + } +} + func logoutHandler(ctx *Context) { user := ctx.User() if user == "" { diff --git a/pkg/server/routes.go b/pkg/server/routes.go index ae88bdc..562afb9 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -89,7 +89,7 @@ var prefixRoutes = []route{ var routes = append(static, []route{ { - "/search", + core.SearchURI, jwtHandler( authHandler( searchHandler)), @@ -122,6 +122,27 @@ var routes = append(static, []route{ userTotpHandler)), []string{"GET", "POST"}, }, + { + "/tags", + jwtHandler( + authHandler( + tagsHandler)), + []string{"GET"}, + }, + { + "/tags/{tag:[a-zA-Z0-9]+}/edit", + jwtHandler( + authHandler( + tagsEditHandler)), + []string{"GET", "POST"}, + }, + { + "/tags/{tag:[a-zA-Z0-9]+}/del", + jwtHandler( + authHandler( + tagsDelHandler)), + []string{"GET", "POST"}, + }, { core.LogoutURI, jwtHandler( diff --git a/pkg/server/templates.go b/pkg/server/templates.go index 69047d9..1166c34 100644 --- a/pkg/server/templates.go +++ b/pkg/server/templates.go @@ -127,6 +127,7 @@ const ( Index {{end}} {{end}} + Raw Move Delete @@ -159,7 +160,7 @@ const ( DocStore | {{.Title}} - + @@ -265,6 +266,9 @@ const ( menu = `{{define "menu"}}
@@ -426,6 +430,86 @@ const ( +{{end}}` + tagsDel = `{{define "body"}} +
+
+
+
+ {{.BodyTitle}} +
+
+ + +
+ + +
+
+ + +
+ + Back + +
+
+
+
+{{end}}` + tagsEdit = `{{define "body"}} +
+
+
+
+ {{.BodyTitle}} +
+
+
+ +
+ + +
+
+ + +
+ + Back +
+
+
+
+
+{{end}}` + tagsList = `{{define "body"}} +
+ + + + + + + + + + {{if .Data}} + {{range $item := .Data}} + {{$len := len $item.Regex}} + + + + + + {{end}} + {{end}} + +
NameRegexOptions
{{$item.Name}}{{printf "%.50s" $item.Regex}}{{if gt $len 50}}...{{end}}
+ Edit + Delete +
+
{{end}}` upload = `{{define "body"}}
@@ -579,7 +663,7 @@ a.anchor { top: -70px; visibility: hidden; } -a.mono { +.mono { font-family: monospace; } .alert-primary { @@ -744,6 +828,10 @@ func (s *HTTPServer) loadTemplates() { s.templ["userEditHandler"] = parse(index, menu, userEdit) // totp s.templ["userTotpHandler"] = parse(index, menu, userTotp) + // tags + s.templ["tagsHandler"] = parse(index, menu, tagsList) + s.templ["tagsEditHandler"] = parse(index, menu, tagsEdit) + s.templ["tagsDelHandler"] = parse(index, menu, tagsDel) if fatal { log.Fatal("parse: ", errors.New("parsing templates failed")) diff --git a/pkg/store/boltstore.go b/pkg/store/boltstore.go index edf1fcb..4d9c006 100644 --- a/pkg/store/boltstore.go +++ b/pkg/store/boltstore.go @@ -119,6 +119,15 @@ func (bs *BoltStore) ForEach(f func(string, []byte) error) error { }) } +func (bs *BoltStore) ForEachPrefix(prefix string, f func(string, []byte) error) error { + return bs.ForEach(func(k string, v []byte) error { + if trim, ok := hasTrimPrefix(k, prefix); ok { + return f(trim, v) + } + return nil + }) +} + func (bs *BoltStore) Delete(key string) error { return bs.db.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte(defaultBoltBucket)).Delete([]byte(key)) diff --git a/pkg/store/gob.go b/pkg/store/gob.go new file mode 100644 index 0000000..9dfdff6 --- /dev/null +++ b/pkg/store/gob.go @@ -0,0 +1,25 @@ +// Copyright (C) 2019 Marius Schellenberger + +package store + +import ( + "bytes" + "encoding/gob" +) + +type gobMarshaler struct{} + +func NewGOB() Marshaler { + return gobMarshaler{} +} + +func (gobMarshaler) Marshal(v interface{}) (b []byte, err error) { + buf := new(bytes.Buffer) + err = gob.NewEncoder(buf).Encode(v) + b = buf.Bytes() + return +} + +func (gobMarshaler) Unmarshal(data []byte, v interface{}) error { + return gob.NewDecoder(bytes.NewBuffer(data)).Decode(v) +} diff --git a/pkg/store/helper.go b/pkg/store/helper.go new file mode 100644 index 0000000..db17a72 --- /dev/null +++ b/pkg/store/helper.go @@ -0,0 +1,11 @@ +// Copyright (C) 2019 Marius Schellenberger + +package store + +// Parts taken from strings.TrimPrefix +func hasTrimPrefix(s, prefix string) (string, bool) { + if len(s) >= len(prefix) && s[0:len(prefix)] == prefix { + return s[len(prefix):], true + } + return s, false +} diff --git a/pkg/store/marshal.go b/pkg/store/marshal.go index b9b56cd..ce68115 100644 --- a/pkg/store/marshal.go +++ b/pkg/store/marshal.go @@ -2,29 +2,7 @@ package store -import ( - "bytes" - "encoding/gob" -) - type Marshaler interface { Marshal(v interface{}) ([]byte, error) Unmarshal(data []byte, v interface{}) error } - -type gobMarshaler struct{} - -func NewGOB() Marshaler { - return gobMarshaler{} -} - -func (gobMarshaler) Marshal(v interface{}) (b []byte, err error) { - buf := new(bytes.Buffer) - err = gob.NewEncoder(buf).Encode(v) - b = buf.Bytes() - return -} - -func (gobMarshaler) Unmarshal(data []byte, v interface{}) error { - return gob.NewDecoder(bytes.NewBuffer(data)).Decode(v) -} diff --git a/pkg/store/store.go b/pkg/store/store.go index 88e8500..4a5f90b 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -17,6 +17,7 @@ type Store interface { Get(string, interface{}) error Set(string, interface{}) error ForEach(func(string, []byte) error) error + ForEachPrefix(string, func(string, []byte) error) error Delete(string) error Close() error } diff --git a/pkg/tags/tags.go b/pkg/tags/tags.go new file mode 100644 index 0000000..160a9bd --- /dev/null +++ b/pkg/tags/tags.go @@ -0,0 +1,18 @@ +// Copyright (C) 2019 Marius Schellenberger + +package tags + +import ( + "git.giftfish.de/ston1th/docstore/pkg/core" + "regexp" +) + +func Find(text string, tags []core.Tag) (found []string) { + for _, t := range tags { + re := regexp.MustCompile(t.Regex) + if re.MatchString(text) { + found = append(found, t.Name) + } + } + return +} diff --git a/templates.sh b/templates.sh index f5b32ba..a5fba53 100755 --- a/templates.sh +++ b/templates.sh @@ -96,6 +96,10 @@ func (s *HTTPServer) loadTemplates() { s.templ["userEditHandler"] = parse(index, menu, userEdit) // totp s.templ["userTotpHandler"] = parse(index, menu, userTotp) + // tags + s.templ["tagsHandler"] = parse(index, menu, tagsList) + s.templ["tagsEditHandler"] = parse(index, menu, tagsEdit) + s.templ["tagsDelHandler"] = parse(index, menu, tagsDel) if fatal { log.Fatal("parse: ", errors.New("parsing templates failed")) diff --git a/templates/custom.css b/templates/custom.css index 1743254..dd4d0e5 100644 --- a/templates/custom.css +++ b/templates/custom.css @@ -41,7 +41,7 @@ a.anchor { top: -70px; visibility: hidden; } -a.mono { +.mono { font-family: monospace; } .alert-primary { diff --git a/templates/file.html b/templates/file.html index 1a0bf6e..f1a0361 100644 --- a/templates/file.html +++ b/templates/file.html @@ -16,6 +16,7 @@ Index {{end}} {{end}} + Raw Move Delete
diff --git a/templates/index.html b/templates/index.html index 7769e89..8ad55ff 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,7 +4,7 @@ DocStore | {{.Title}} - + diff --git a/templates/menu.html b/templates/menu.html index 8719c1c..2749e04 100644 --- a/templates/menu.html +++ b/templates/menu.html @@ -1,6 +1,9 @@ {{define "menu"}}
diff --git a/templates/tagsDel.html b/templates/tagsDel.html new file mode 100644 index 0000000..8793c85 --- /dev/null +++ b/templates/tagsDel.html @@ -0,0 +1,26 @@ +{{define "body"}} +
+
+
+
+ {{.BodyTitle}} +
+
+ + +
+ + +
+
+ + +
+ + Back + +
+
+
+
+{{end}} diff --git a/templates/tagsEdit.html b/templates/tagsEdit.html new file mode 100644 index 0000000..8793c85 --- /dev/null +++ b/templates/tagsEdit.html @@ -0,0 +1,26 @@ +{{define "body"}} +
+
+
+
+ {{.BodyTitle}} +
+
+
+ +
+ + +
+
+ + +
+ + Back +
+
+
+
+
+{{end}} diff --git a/templates/tagsList.html b/templates/tagsList.html new file mode 100644 index 0000000..e543438 --- /dev/null +++ b/templates/tagsList.html @@ -0,0 +1,28 @@ +{{define "body"}} +
+ + + + + + + + + + {{if .Data}} + {{range $item := .Data}} + {{$len := len $item.Regex}} + + + + + + {{end}} + {{end}} + +
NameRegexOptions
{{$item.Name}}{{printf "%.50s" $item.Regex}}{{if gt $len 50}}...{{end}}
+ Edit + Delete +
+
+{{end}}