diff --git a/README.md b/README.md index 200275c..38f3726 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ ## Building +**Requirements:** + +* Go (golang) >= 1.12 + Linux: ``` @@ -46,6 +50,19 @@ See the `scripts/` directory on how to install docstore on Linux or OpenBSD. } ``` +## Features + +* Fulltext indexing of documents +* Custom regex based tags (see https://golang.org/pkg/regexp/syntax/) +* Password hashing using BCrypt +* 2FA using TOTP +* Content Security Policy +* No Javascript (yet) + +### DocStore on OpenBSD + +DocStore makes use of the OpenBSD native security features [pledge(2)](https://man.openbsd.org/pledge) and [unveil(2)](https://man.openbsd.org/unveil). + ## Usage DocStore manages all files and directories under the `$run_dir/data` directory. diff --git a/img/favicon_16x16.png b/img/favicon_16x16.png new file mode 100644 index 0000000..5d31a2f Binary files /dev/null and b/img/favicon_16x16.png differ diff --git a/img/favicon_32x32.png b/img/favicon_32x32.png new file mode 100644 index 0000000..cbf0c06 Binary files /dev/null and b/img/favicon_32x32.png differ diff --git a/pkg/core/const.go b/pkg/core/const.go index 92043c5..53540b9 100644 --- a/pkg/core/const.go +++ b/pkg/core/const.go @@ -12,13 +12,14 @@ const ( TagsURI = "/tags" UserURI = "/user" - RawPrefix = "/raw" - IndexPrefix = "/index" - UploadPrefix = "/upload" - NewPrefix = "/new" - MovePrefix = "/move" - TagsPrefix = "/tags" - DeletePrefix = "/delete" + RawPrefix = "/raw" + IndexPrefix = "/index" + ReindexPrefix = "/reindex" + UploadPrefix = "/upload" + NewPrefix = "/new" + MovePrefix = "/move" + TagsPrefix = "/tags" + DeletePrefix = "/delete" Favicon = "/favicon.ico" BootstrapCSS = "/bootstrap.css" diff --git a/pkg/db/index.go b/pkg/db/index.go index fe32cfb..91bc027 100644 --- a/pkg/db/index.go +++ b/pkg/db/index.go @@ -3,14 +3,72 @@ package db import ( + "errors" "git.giftfish.de/ston1th/docstore/pkg/core" + "git.giftfish.de/ston1th/docstore/pkg/log" + "git.giftfish.de/ston1th/docstore/pkg/tags" ) const ( - idPrefix = "id/" + // schema: + // key: id/ + // value: + idPrefix = "id/" + // schema: + // key: path/ + // value: pathPrefix = "path/" ) +func (db *DB) Reindex(path string, match []core.Tag) (err error) { + if match == nil { + match, err = db.GetAllTags() + if err != nil { + return + } + } + id, err := db.GetID(path) + if err != nil { + return + } + log.Debugf("db: reindexing: %s", path) + doc, err := db.Index.Get(id) + if err != nil { + return + } + doc.Tags = tags.Find(doc.Text, match) + err = db.Index.Reindex(id, doc) + if err != nil { + return + } + return db.SetTag(path, doc.Tags) +} + +func (db *DB) ReindexAll() (err error) { + var paths []string + err = db.store.ForEachPrefix(idPrefix, func(k string, _ []byte) error { + paths = append(paths, k) + return nil + }) + if err != nil { + return + } + match, err := db.GetAllTags() + if err != nil { + return + } + for _, p := range paths { + e := db.Reindex(p, match) + if e != nil { + if err == nil { + err = errors.New("reindexAll had errors") + } + log.Printf("db: error reindexing %s: %s", p, e) + } + } + return +} + func (db *DB) GetPaths(res []core.Result) { for i, v := range res { err := db.store.Get(pathPrefix+v.ID, &res[i].Path) @@ -49,7 +107,7 @@ func (db *DB) DeleteID(path string) error { return db.store.Delete(idPrefix + path) } -func (db *DB) NewFile(id, path string, tags []string) (err error) { +func (db *DB) NewFile(id, path string, tag []string) (err error) { err = db.store.Set(idPrefix+path, id) if err != nil { return @@ -58,21 +116,21 @@ func (db *DB) NewFile(id, path string, tags []string) (err error) { if err != nil { return } - return db.SetTag(path, tags) + return db.SetTag(path, tag) } func (db *DB) MoveFile(op, np string) (err error) { if !db.IsIndexed(op) { return nil } - id, tags, err := db.DeleteFile(op) + id, tag, err := db.DeleteFile(op) if err != nil { return } - return db.NewFile(id, np, tags) + return db.NewFile(id, np, tag) } -func (db *DB) DeleteFile(path string) (id string, tags []string, err error) { +func (db *DB) DeleteFile(path string) (id string, tag []string, err error) { if !db.IsIndexed(path) { return } @@ -84,7 +142,7 @@ func (db *DB) DeleteFile(path string) (id string, tags []string, err error) { if err != nil { return } - tags, err = db.UnsetTag(path) + tag, err = db.UnsetTag(path) if err != nil { return } diff --git a/pkg/db/migration.go b/pkg/db/migration.go index 4dfa638..eca5e22 100644 --- a/pkg/db/migration.go +++ b/pkg/db/migration.go @@ -22,8 +22,12 @@ var migrators = []migrator{ // dummy placeholder return nil }, - func(db *DB) error { - return db.addDefaultTags() + func(db *DB) (err error) { + err = db.addDefaultTags() + if err != nil { + return + } + return db.ReindexAll() }, } @@ -43,7 +47,7 @@ func (db *DB) runMigrations() (err error) { log.Printf("db: database version %d", version) for version < currentVersion { v := version + 1 - log.Printf("db: running migration %d", v) + log.Printf("db: running migration version %d", v) err = migrators[v](db) if err != nil { return @@ -52,6 +56,8 @@ func (db *DB) runMigrations() (err error) { if err != nil { return } + version = v + log.Printf("db: database version %d", version) } return } diff --git a/pkg/fs/helper.go b/pkg/fs/helper.go index 44521e6..4d7c3a4 100644 --- a/pkg/fs/helper.go +++ b/pkg/fs/helper.go @@ -30,6 +30,7 @@ var reserved = []string{ core.UserURI, core.RawPrefix, core.IndexPrefix, + core.ReindexPrefix, core.UploadPrefix, core.NewPrefix, core.MovePrefix, diff --git a/pkg/index/index.go b/pkg/index/index.go index 97f6381..ea717f3 100644 --- a/pkg/index/index.go +++ b/pkg/index/index.go @@ -6,6 +6,7 @@ import ( "errors" "git.giftfish.de/ston1th/docstore/pkg/core" "github.com/blevesearch/bleve" + "github.com/blevesearch/bleve/document" "github.com/blevesearch/bleve/mapping" "html/template" "os" @@ -17,13 +18,13 @@ const maxSearchResult = 101 const docType = "document" -type document struct { +type Document struct { Text string `json:"text"` Tags []string `json:"tags"` Created time.Time `json:"created"` } -func (d *document) Type() string { +func (d *Document) Type() string { return docType } @@ -70,7 +71,34 @@ func (i *Index) Add(text string, tags []string) (id string, err error) { } id = newID() } - err = i.i.Index(id, &document{text, tags, time.Now()}) + err = i.i.Index(id, &Document{text, tags, time.Now()}) + return +} + +func (i *Index) Reindex(id string, doc *Document) error { + return i.i.Index(id, doc) +} + +func (i *Index) Get(id string) (doc *Document, err error) { + d, err := i.i.Document(id) + if d == nil || err != nil { + return + } + doc = new(Document) + for _, f := range d.Fields { + n := f.Name() + switch n { + case "text": + text := document.NewTextField(n, f.ArrayPositions(), f.Value()) + doc.Text = string(text.Value()) + //case "tags": + // tags := document.NewTextField(n, f.ArrayPositions(), f.Value()) + // doc.Tags = append(doc.Tags, string(tags.Value())) + case "created": + created := document.NewDateTimeFieldFromBytes(n, f.ArrayPositions(), f.Value()) + doc.Created, _ = created.DateTime() + } + } return } diff --git a/pkg/server/context.go b/pkg/server/context.go index 64adc5e..77409bb 100644 --- a/pkg/server/context.go +++ b/pkg/server/context.go @@ -13,6 +13,7 @@ import ( "net/http" "net/url" "reflect" + "strconv" "time" ) @@ -59,7 +60,7 @@ type Context struct { type webData struct { Version string - Time int64 + Time string Title string BodyTitle string @@ -98,7 +99,12 @@ func (c *Context) Exec() { } c.Data.User = c.User() c.Data.Login = c.LoggedOn() - c.Data.Time = time.Since(c.Time).Nanoseconds() / 1e6 + + t := strconv.Itoa(int(time.Since(c.Time).Nanoseconds()/1e6)) + "ms" + if t == "0ms" { + t = strconv.Itoa(int(time.Since(c.Time).Nanoseconds()/1e5)) + "µs" + } + c.Data.Time = t if c.Data.Msg != "" { c.Status(http.StatusBadRequest) diff --git a/pkg/server/handler.go b/pkg/server/handler.go index 341c0d9..e1c8763 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -206,11 +206,26 @@ func scanFile(ctx *Context, path string) (err error) { } func indexHandler(ctx *Context) { - path := strings.TrimPrefix(ctx.Path(), core.IndexPrefix) switch ctx.Method() { case "GET": - err := scanFile(ctx, path) - p, _ := filepath.Split(path) + var ( + err error + fpath string + ) + path := ctx.Path() + if strings.HasPrefix(path, core.IndexPrefix) { + fpath = strings.TrimPrefix(path, core.IndexPrefix) + err = scanFile(ctx, fpath) + } + if strings.HasPrefix(path, core.ReindexPrefix) { + fpath = strings.TrimPrefix(path, core.ReindexPrefix) + if fpath == "" { + err = ctx.Srv.DB.ReindexAll() + } else { + err = ctx.Srv.DB.Reindex(fpath, nil) + } + } + p, _ := filepath.Split(fpath) p = filepath.Dir(p) if err != nil { ctx.Template("iseHandler") @@ -429,10 +444,10 @@ func dirHandler(ctx *Context) { } switch mode { case fs.IsDir: - ctx.Data = webData{ - Title: "Directory Viewer", - } dir := ctx.Srv.FS.ReadDir(path) + ctx.Data = webData{ + Title: "Directory Viewer | " + path, + } ctx.Srv.DB.GetIndexed(dir.Files) ctx.Data.Path = path ctx.Data.Data = dir @@ -440,7 +455,7 @@ func dirHandler(ctx *Context) { ctx.Exec() case fs.IsFile: ctx.Data = webData{ - Title: "Document Viewer", + Title: "Document Viewer | " + path, } ctx.Template("fileHandler") ctx.Data.Data = core.Path{ @@ -566,12 +581,12 @@ func searchHandler(ctx *Context) { if !ctx.CheckXsrf() { return } - ctx.Data.Search = ctx.Form("search") - if ctx.Data.Search == "" { - ctx.Error("empty search request") - return + s := ctx.Form("search") + ctx.Data.Search = s + if s == "" { + s = `""` } - res, err := ctx.Srv.DB.Index.Search(ctx.Data.Search) + res, err := ctx.Srv.DB.Index.Search(s) if err != nil { ctx.Error(err) return diff --git a/pkg/server/routes.go b/pkg/server/routes.go index e4e5a00..fbc4213 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -48,7 +48,14 @@ var prefixRoutes = []route{ jwtHandler( authHandler( indexHandler)), - []string{"GET", "POST"}, + []string{"GET"}, + }, + { + core.ReindexPrefix, + jwtHandler( + authHandler( + indexHandler)), + []string{"GET"}, }, { core.UploadPrefix, diff --git a/pkg/server/templates.go b/pkg/server/templates.go index 0a072cb..b546bbe 100644 --- a/pkg/server/templates.go +++ b/pkg/server/templates.go @@ -48,9 +48,14 @@ const (
Upload - New + New Directory + {{$pl := len .Paths}} + {{if eq $pl 0}} + Reindex All + {{else}} Move Delete + {{end}}
@@ -130,7 +135,9 @@ const ( {{if .Data.Scan}} Scanning {{else}} - {{if not .Data.Flag}} + {{if .Data.Flag}} + Reindex + {{else}} Index {{end}} {{end}} @@ -198,7 +205,7 @@ const (
  • Back to top
  • Git
  • -

    © DocStore {{.Version}} Request: {{.Time}}ms

    +

    © DocStore {{.Version}} Request: {{.Time}}

    @@ -445,11 +452,24 @@ const ( {{$item.Tags}} {{end}} - {{else}} - No search results found. - {{end}} + {{else}} + No search results found. + +
    +
    +
    +

    Query Syntax

    +

    Fields

    +
    tags:insurance
    +tags:insurance or tags:invoice
    +created:<="2016-09-21"
    +

    Fulltext

    +
    some text here
    +
    +
    + {{end}}
    {{end}}` tagsDel = `{{define "body"}} @@ -836,7 +856,7 @@ html, body, .container, .content { top: 38%; transform: translateY(-50%); }` - favicon = "AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaNSJ/Wjf/f1o3/39aN/+AWThyAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////4P4P/+D+D//gfgf/wHwH/8B8B//APAf/gDgD/4A4A/+BOAP/gRAR/wEQMf8DEDH/A4A4/gOAeP4HgHj+B8B8/AfA/HwPwPxwA+DwH/////////////////////////////////////KAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgAACf1o36YBaN+YAAAABAAAAAAAAAACAWzdwf1o3/35bNl8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFk3PH9aN/9/Wjf/gFs3OAAAAAAAAAAAf1o3wX9aN/9/WjevAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH9aN4t/Wjf/gFo39oBaNogAAAAAgFkzFIBaN/x/Wjf/f1o35XFVOQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjfaf1o3/39ZOImAWjjKAAAAAH5ZN2F/Wjf/f1o38X5bN3l+WjdPAAAAAAAAAAAAAAAAAAAAAAAAAACAWzcqf1o3/39aN/+AWDY0f1o3rYBZOSh/WTexf1o3/4BaOKp8VzojgFo3ngAAAAAAAAAAAAAAAAAAAAAAAAAAgFo2en9aN/9/WjfjAAAAAH5ZN2GAWjeCgFo39n9aN/+AWjZeAAAAAIBaNsBVVVUDAAAAAAAAAAAAAAAAAAAAAH9aN8l/Wjf/gFo3lAAAAACAXToWgFo39H9aN/9/Wjf9gFkzFAAAAACAWzaEfVk5PwAAAAAAAAAAAAAAAIBYOxqAWjf+f1o3/35bNUMAAAAAAAAAAIBaOMp/Wjf/gFo3xgAAAAAAAAAAgFg2NH9ZN48AAAAAAAAAAIBbNxx/Wjf/f1o3/39aN/9/Wjf/gFVADAAAAACAWTd+f1o3/35bN3kAAAAAgFU1GH9aN/9/Wjf/gFk4oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA4Y8AAOGPAADhBwAA4QcAAMAHAADEEwAAxBMAAIYzAAACIQAA//8AAP//AAD//wAA" + favicon = "AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgEBABH9aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf9gFo37oBaNtyAWzfIgFo2loBZN1yAWzccAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAQEAEf1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/2AWjewfVk5PwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAgFUrBoBVNRh9XDYvgFs2aIBaN6x/Wjf7f1o3/39aN/9/Wjf/gFo2pIBbNw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBYOCB/Wzejf1o3/39aN/9/Wjf/gFo33nxXOiMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+Wzdrf1o3/X9aN/9/Wjf/gFo32nleNhMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+Wjd9f1o3/39aN/9/Wjf/gFo3ugAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAAAKAWjfGf1o3/39aN/9/Wjf/gFk5SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBcOE5/Wjf/f1o3/39aN/+AWjjKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX9aN+V/Wjf/f1o3/39aN/97XjkbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf1s2qX9aN/9/Wjf/f1o3/35ZN2EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWThyf1o3/39aN/9/Wjf/gFo2lgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH5aOFt/Wjf/f1o3/39aN/9/WTerAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3Sn9aN/9/Wjf/f1o3/4BaNsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWTlIf1o3/39aN/9/Wjf/f1o3wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBbNlp/Wjf/f1o3/39aN/+AWjesAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFs3cH9aN/9/Wjf/f1o3/39aOJcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWzemf1o3/39aN/9/Wjf/fls4ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN+J/Wjf/f1o3/39aN/97WDUdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+WzhJf1o3/39aN/9/Wjf/f1o3zQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBZN8J/Wjf/f1o3/39aN/9+WDZLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+Wzd5f1o3/39aN/9/Wjf/f1o3vQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaN6x/Wjf/f1o3/4BZN+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFs2aIBaN/x/Wjf/f1o3/39aN9uAWTMUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo3rH9aN/9/Wjf/gFk35AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAe1o6H39aN6F/Wjf/f1o3/39aN/9/WjfdfFc6IwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjesf1o3/39aN/+AWTfkAAAAAAAAAAAAAAAAgFUrBnpcMxmAWjUwflo4aX9ZN6uAWjf6f1o3/39aN/9/Wjf/gFo2pIBbNw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgEBABH9aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf9f1o3r31ZOT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAQEAEf1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/9/Wjf/f1o3/39aN/1/Wjftf1o324BbN8iAWjaWgFk3XIBbNxwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////+AAB//gAAH//hwAf/4f4D/+H/gf/h/8H/4f/A/+H/4P/h/+B/4f/wf+H/8H/h//B/4f/wf+H/8H/h//B/4f/wf+H/8H/h//B/4f/g/+H/wP/h/8H/4f+B/+H+A//hwAf+AAAf/gAAf/////////////////KAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWzccf1o3/39aN/9/Wjf/f1o3/4BaN/6AWjfuf1s2xYBbNnaAWzcOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWTiggFo39AAAAABVVVUDe145G4BbN2KAWjfigFo34H1bOS0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFk4oIBaN/QAAAAAAAAAAAAAAAAAAAAAelk3F4BaN+KAWjfidmI7DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBZOKCAWjf0AAAAAAAAAAAAAAAAAAAAAAAAAAB+Wjddf1o3/4BaN3QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWTiggFo39AAAAAAAAAAAAAAAAAAAAAAAAAAAd1UzD4BaN/6AWje+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFk4oIBaN/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/Wjftf1o33QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBZOKCAWjf0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFo37H9aN90AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWTiggFo39AAAAAAAAAAAAAAAAAAAAAAAAAAAgFs3DoBaN/6AWje+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFk4oIBaN/QAAAAAAAAAAAAAAAAAAAAAAAAAAIBbNlp/Wjf/flk2dQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBZOKCAWjf0AAAAAAAAAAAAAAAAAAAAAIBdOhaAWjfgf1o343ZiOw0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWTiggFo39AAAAABVVVUDe145G4BbN2J/WjjhgFo34H1bOS0AAAAAAAAAAAAAAAAAAAAAAAAAAIBbNxx/Wjf/f1o3/39aN/9/Wjf/f1o3/YBaN+6AWjfEgFs2doBbNw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAMAPAADyBwAA88MAAPPjAADz4wAA8/MAAPPzAADz4wAA8+MAAPPDAADyBwAAwA8AAP//AAD//wAA" ) func (s *HTTPServer) loadTemplates() { diff --git a/templates/dir.html b/templates/dir.html index aac49f2..b2ff7ba 100644 --- a/templates/dir.html +++ b/templates/dir.html @@ -10,9 +10,14 @@
    Upload - New + New Directory + {{$pl := len .Paths}} + {{if eq $pl 0}} + Reindex All + {{else}} Move Delete + {{end}}
    diff --git a/templates/favicon.ico b/templates/favicon.ico index a8a1b4e..30ac420 100644 Binary files a/templates/favicon.ico and b/templates/favicon.ico differ diff --git a/templates/file.html b/templates/file.html index f1a0361..e414100 100644 --- a/templates/file.html +++ b/templates/file.html @@ -12,7 +12,9 @@ {{if .Data.Scan}} Scanning {{else}} - {{if not .Data.Flag}} + {{if .Data.Flag}} + Reindex + {{else}} Index {{end}} {{end}} diff --git a/templates/index.html b/templates/index.html index ec43c3c..d1fd8c7 100644 --- a/templates/index.html +++ b/templates/index.html @@ -35,7 +35,7 @@
  • Back to top
  • Git
  • -

    © DocStore {{.Version}} Request: {{.Time}}ms

    +

    © DocStore {{.Version}} Request: {{.Time}}

    diff --git a/templates/search.html b/templates/search.html index 65f688d..4192622 100644 --- a/templates/search.html +++ b/templates/search.html @@ -40,10 +40,23 @@ {{$item.Tags}} {{end}} - {{else}} - No search results found. - {{end}} + {{else}} + No search results found. + +
    +
    +
    +

    Query Syntax

    +

    Fields

    +
    tags:insurance
    +tags:insurance or tags:invoice
    +created:<="2016-09-21"
    +

    Fulltext

    +
    some text here
    +
    +
    + {{end}}
    {{end}}