finished tag implementation
This commit is contained in:
parent
b3b62af3a4
commit
c3076c328a
28 changed files with 396 additions and 296 deletions
34
go.mod
34
go.mod
|
|
@ -1,34 +0,0 @@
|
||||||
module git.giftfish.de/ston1th/docstore
|
|
||||||
|
|
||||||
go 1.12
|
|
||||||
|
|
||||||
require (
|
|
||||||
git.giftfish.de/ston1th/godrop/v2 v2.1.0
|
|
||||||
git.giftfish.de/ston1th/jwt/v3 v3.2.0
|
|
||||||
github.com/RoaringBitmap/roaring v0.4.17 // indirect
|
|
||||||
github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1 // indirect
|
|
||||||
github.com/blevesearch/bleve v0.7.0
|
|
||||||
github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3 // indirect
|
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.2 // indirect
|
|
||||||
github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f // indirect
|
|
||||||
github.com/boltdb/bolt v1.3.1
|
|
||||||
github.com/boombuler/barcode v1.0.0 // indirect
|
|
||||||
github.com/couchbase/vellum v0.0.0-20190328134517-462e86d8716b // indirect
|
|
||||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect
|
|
||||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
|
|
||||||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect
|
|
||||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
|
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
|
||||||
github.com/golang/protobuf v1.3.1 // indirect
|
|
||||||
github.com/gorilla/mux v1.7.1
|
|
||||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
|
||||||
github.com/pquerna/otp v1.1.0
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect
|
|
||||||
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect
|
|
||||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
|
||||||
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect
|
|
||||||
github.com/urfave/cli v1.20.0
|
|
||||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734
|
|
||||||
)
|
|
||||||
116
go.sum
116
go.sum
|
|
@ -1,116 +0,0 @@
|
||||||
git.giftfish.de/ston1th/godrop/v2 v2.1.0 h1:vR4aWVeMGJ+tHQH0p44esZrSl5dYJzuCmZqhKWP/vwI=
|
|
||||||
git.giftfish.de/ston1th/godrop/v2 v2.1.0/go.mod h1:z8KA3HP/vB04wddLXZfYVKURYDxBGau9hlHtV61x9mM=
|
|
||||||
git.giftfish.de/ston1th/jwt/v3 v3.2.0 h1:V6Lh7OjXn4D3HPd/LoDf7w5N7cyiSXEPAQCIfSVZ05c=
|
|
||||||
git.giftfish.de/ston1th/jwt/v3 v3.2.0/go.mod h1:jDALrW7OKeIaqYuMxs3GWyPRnQZmk/R+Lu9p/Em3Ziw=
|
|
||||||
github.com/RoaringBitmap/roaring v0.4.17 h1:oCYFIFEMSQZrLHpywH7919esI1VSrQZ0pJXkZPGIJ78=
|
|
||||||
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
|
||||||
github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1 h1:G/NOANWMQev0CftoyxQwtRakdyNNNMB3qxkt/tj1HGs=
|
|
||||||
github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1/go.mod h1:o80NPAib/LOl8Eysqppjj7kkGkqz++eqzYGlvROpDcQ=
|
|
||||||
github.com/blevesearch/bleve v0.7.0 h1:znyZ3zjsh2Scr60vszs7rbF29TU6i1q9bfnZf1vh0Ac=
|
|
||||||
github.com/blevesearch/bleve v0.7.0/go.mod h1:Y2lmIkzV6mcNfAnAdOd+ZxHkHchhBfU/xroGIp61wfw=
|
|
||||||
github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3 h1:U6vnxZrTfItfiUiYx0lf/LgHjRSfaKK5QHSom3lEbnA=
|
|
||||||
github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3/go.mod h1:WH+MU2F4T0VmSdaPX+Wu5GYoZBrYWdOZWSjzvYcDmqQ=
|
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.2 h1:qe7n69gBd1OLY5sHKnxQHIbzn0LNJA4hpAf+5XDxV2I=
|
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.2/go.mod h1:haWQqFT3RdOGz7PJuM3or/pWNJS1pKkoZJWCkWu0DVA=
|
|
||||||
github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f h1:kqbi9lqXLLs+zfWlgo1PIiRQ86n33K1JKotjj4rSYOg=
|
|
||||||
github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f/go.mod h1:IInt5XRvpiGE09KOk9mmCMLjHhydIhNPKPPFLFBB7L8=
|
|
||||||
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
|
||||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
|
||||||
github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
|
|
||||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
|
||||||
github.com/couchbase/vellum v0.0.0-20190328134517-462e86d8716b h1:WgO2yt0pCXyPgU3K/pnY1qO/8FP8TxBAaYXqa+BQpx0=
|
|
||||||
github.com/couchbase/vellum v0.0.0-20190328134517-462e86d8716b/go.mod h1:prYTC8EgTu3gwbqJihkud9zRXISvyulAplQ6exdCo1g=
|
|
||||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
|
|
||||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
|
||||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
|
|
||||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
|
||||||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM=
|
|
||||||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
|
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
|
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
|
||||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493 h1:OTanQnFt0bi5iLFSdbEVA/idR6Q2WhCm+deb7ir2CcM=
|
|
||||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU=
|
|
||||||
github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
|
|
||||||
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
|
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/pquerna/otp v1.1.0 h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0=
|
|
||||||
github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ=
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys=
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
|
|
||||||
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 h1:JNEGSiWg6D3lcBCMCBqN3ELniXujt+0QNHLhNnO0w3s=
|
|
||||||
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
|
||||||
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0=
|
|
||||||
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
|
|
||||||
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
|
||||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
|
||||||
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
|
|
||||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
|
|
@ -253,7 +253,7 @@ func serverFlags() []cli.Flag {
|
||||||
},
|
},
|
||||||
cli.StringSliceFlag{
|
cli.StringSliceFlag{
|
||||||
Name: "langs",
|
Name: "langs",
|
||||||
Usage: "languages for tesseract ocr",
|
Usage: "languages for tesseract ocr (use --langs multiple times to add more languages)",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
Name: "timeout, t",
|
Name: "timeout, t",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const (
|
||||||
LoginURI = "/login"
|
LoginURI = "/login"
|
||||||
LogoutURI = "/logout"
|
LogoutURI = "/logout"
|
||||||
SearchURI = "/search"
|
SearchURI = "/search"
|
||||||
|
LogsURI = "/logs"
|
||||||
TagsURI = "/tags"
|
TagsURI = "/tags"
|
||||||
UserURI = "/user"
|
UserURI = "/user"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fileFmt = "20060102_150405"
|
fileFmt = "20060102_150405"
|
||||||
|
logFmt = "2006/01/02 15:04:05: "
|
||||||
)
|
)
|
||||||
|
|
||||||
var m sync.Mutex
|
var m sync.Mutex
|
||||||
|
|
@ -21,3 +22,7 @@ func FileName() string {
|
||||||
}()
|
}()
|
||||||
return time.Now().Format(fileFmt)
|
return time.Now().Format(fileFmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LogTime() string {
|
||||||
|
return time.Now().Format(logFmt)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ type Path struct {
|
||||||
Abs string
|
Abs string
|
||||||
Flag bool
|
Flag bool
|
||||||
Scan bool
|
Scan bool
|
||||||
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Paths []Path
|
type Paths []Path
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,19 @@ const (
|
||||||
pathPrefix = "path/"
|
pathPrefix = "path/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (db *DB) GetPaths(res []core.Result) error {
|
func (db *DB) GetPaths(res []core.Result) {
|
||||||
for i, v := range res {
|
for i, v := range res {
|
||||||
err := db.store.Get(pathPrefix+v.ID, &res[i].Path)
|
err := db.store.Get(pathPrefix+v.ID, &res[i].Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
res[i].Path = err.Error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) GetIndexed(p core.Paths) {
|
func (db *DB) GetIndexed(p core.Paths) {
|
||||||
for i, v := range p {
|
for i, v := range p {
|
||||||
p[i].Flag = db.IsIndexed(v.Abs)
|
p[i].Flag = db.IsIndexed(v.Abs)
|
||||||
|
p[i].Tags, _ = db.GetTag(v.Abs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,22 +65,14 @@ func (db *DB) MoveFile(op, np string) (err error) {
|
||||||
if !db.IsIndexed(op) {
|
if !db.IsIndexed(op) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
id, err := db.DeleteFile(op)
|
id, tags, err := db.DeleteFile(op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tags, err := db.GetTag(op)
|
return db.NewFile(id, np, tags)
|
||||||
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) {
|
func (db *DB) DeleteFile(path string) (id string, tags []string, err error) {
|
||||||
if !db.IsIndexed(path) {
|
if !db.IsIndexed(path) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +84,7 @@ func (db *DB) DeleteFile(path string) (id string, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = db.UnsetTag(path)
|
tags, err = db.UnsetTag(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,11 @@ func (db *DB) GetAllTags() (tags []core.Tag, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) GetTags(name string) (t core.Tag, err error) {
|
||||||
|
err = db.store.Get(tagsPrefix+name, &t)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (db *DB) DeleteTag(name string) error {
|
func (db *DB) DeleteTag(name string) error {
|
||||||
return db.store.Delete(tagsPrefix + name)
|
return db.store.Delete(tagsPrefix + name)
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +69,11 @@ func (db *DB) SetTag(path string, tags []string) error {
|
||||||
return db.store.Set(tagPrefix+path, tags)
|
return db.store.Set(tagPrefix+path, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) UnsetTag(path string) error {
|
func (db *DB) UnsetTag(path string) (tags []string, err error) {
|
||||||
return db.store.Delete(tagPrefix + path)
|
tags, err = db.GetTag(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.store.Delete(tagPrefix + path)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ type Directory struct {
|
||||||
|
|
||||||
type Filesystem struct {
|
type Filesystem struct {
|
||||||
Base string
|
Base string
|
||||||
|
Log *log.ScanLog
|
||||||
|
|
||||||
// protects scan
|
// protects scan
|
||||||
m sync.RWMutex
|
m sync.RWMutex
|
||||||
|
|
@ -53,7 +54,7 @@ func NewFilesystem(base string) (fs *Filesystem, err error) {
|
||||||
err = errors.New("base dir '" + base + "' is not a directory")
|
err = errors.New("base dir '" + base + "' is not a directory")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fs = &Filesystem{Base: base, scan: make(map[string]struct{})}
|
fs = &Filesystem{Base: base, Log: log.NewScanLog(0), scan: make(map[string]struct{})}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ var reserved = []string{
|
||||||
core.LoginURI,
|
core.LoginURI,
|
||||||
core.LogoutURI,
|
core.LogoutURI,
|
||||||
core.SearchURI,
|
core.SearchURI,
|
||||||
|
core.LogsURI,
|
||||||
core.TagsURI,
|
core.TagsURI,
|
||||||
core.UserURI,
|
core.UserURI,
|
||||||
core.RawPrefix,
|
core.RawPrefix,
|
||||||
|
|
|
||||||
47
pkg/log/scanlog.go
Normal file
47
pkg/log/scanlog.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"git.giftfish.de/ston1th/docstore/pkg/core"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultSize = 500
|
||||||
|
|
||||||
|
type ScanLog struct {
|
||||||
|
// protects logs
|
||||||
|
sync.RWMutex
|
||||||
|
|
||||||
|
size int
|
||||||
|
logs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScanLog(size int) *ScanLog {
|
||||||
|
if size <= 0 {
|
||||||
|
size = defaultSize
|
||||||
|
}
|
||||||
|
return &ScanLog{size: size}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ScanLog) Printf(f string, v ...interface{}) {
|
||||||
|
s := fmt.Sprintf(f, v...)
|
||||||
|
Println(s)
|
||||||
|
s = core.LogTime() + s
|
||||||
|
l.Lock()
|
||||||
|
logsLen := len(l.logs)
|
||||||
|
if logsLen < l.size {
|
||||||
|
l.logs = append(l.logs, s)
|
||||||
|
} else if logsLen == l.size {
|
||||||
|
l.logs = append(l.logs[1:], s)
|
||||||
|
}
|
||||||
|
l.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ScanLog) Logs() (logs string) {
|
||||||
|
l.RLock()
|
||||||
|
for _, v := range l.logs {
|
||||||
|
logs += "\n" + v
|
||||||
|
}
|
||||||
|
l.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -3,10 +3,35 @@
|
||||||
package scan
|
package scan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
pdfContentType = "application/pdf"
|
||||||
|
maxSniffSize = 512
|
||||||
|
)
|
||||||
|
|
||||||
func isPDF(path string) bool {
|
func isPDF(path string) bool {
|
||||||
|
return checkContentType(path) || checkExtension(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkContentType(path string) bool {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
buf := make([]byte, maxSniffSize)
|
||||||
|
_, err = f.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return http.DetectContentType(buf) == pdfContentType
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkExtension(path string) bool {
|
||||||
return strings.ToLower(filepath.Ext(path)) == pdfExt
|
return strings.ToLower(filepath.Ext(path)) == pdfExt
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ func New(c core.Config) (s *Scanner, err error) {
|
||||||
langs := c.Langs
|
langs := c.Langs
|
||||||
if langs == nil || llen == 0 {
|
if langs == nil || llen == 0 {
|
||||||
langs = defaultLangs
|
langs = defaultLangs
|
||||||
|
llen = len(langs)
|
||||||
}
|
}
|
||||||
for i, l := range langs {
|
for i, l := range langs {
|
||||||
lang += l
|
lang += l
|
||||||
|
|
|
||||||
|
|
@ -174,49 +174,45 @@ func rawHandler(ctx *Context) {
|
||||||
http.ServeContent(ctx.Response, ctx.Request, fi.Name(), fi.ModTime(), f)
|
http.ServeContent(ctx.Response, ctx.Request, fi.Name(), fi.ModTime(), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func scanFile(ctx *Context, path string) (err error) {
|
||||||
|
err = ctx.Srv.FS.AddScan(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
defer ctx.Srv.FS.RemoveScan(path)
|
||||||
|
l := ctx.Srv.FS.Log
|
||||||
|
file, txt, err := ctx.Srv.Scanner.Scan(path)
|
||||||
|
if err != nil {
|
||||||
|
l.Printf("scanner: %s: %s", path, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t, err := ctx.Srv.DB.GetAllTags()
|
||||||
|
if err != nil {
|
||||||
|
l.Printf("getTags: %s: %s", path, err)
|
||||||
|
}
|
||||||
|
found := tags.Find(txt, t)
|
||||||
|
id, err := ctx.Srv.DB.Index.Add(txt, found)
|
||||||
|
if err != nil {
|
||||||
|
l.Printf("index: %s: %s", path, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ctx.Srv.DB.NewFile(id, file, found)
|
||||||
|
if err != nil {
|
||||||
|
l.Printf("newFile: %s: %s", path, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func indexHandler(ctx *Context) {
|
func indexHandler(ctx *Context) {
|
||||||
path := strings.TrimPrefix(ctx.Path(), core.IndexPrefix)
|
path := strings.TrimPrefix(ctx.Path(), core.IndexPrefix)
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
case "GET":
|
case "GET":
|
||||||
earlyErr := make(chan error)
|
err := scanFile(ctx, path)
|
||||||
go func() {
|
|
||||||
err := ctx.Srv.FS.AddScan(path)
|
|
||||||
if err != nil {
|
|
||||||
select {
|
|
||||||
case earlyErr <- err:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer ctx.Srv.FS.RemoveScan(path)
|
|
||||||
file, txt, err := ctx.Srv.Scanner.Scan(path)
|
|
||||||
if err != nil {
|
|
||||||
select {
|
|
||||||
case earlyErr <- err:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
log.Printf("scanner: %s: %s", path, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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, found)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("newFile: %s: %s", path, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
p, _ := filepath.Split(path)
|
p, _ := filepath.Split(path)
|
||||||
p = filepath.Dir(p)
|
p = filepath.Dir(p)
|
||||||
select {
|
if err != nil {
|
||||||
case err := <-earlyErr:
|
|
||||||
ctx.Template("iseHandler")
|
ctx.Template("iseHandler")
|
||||||
ctx.Data = webData{
|
ctx.Data = webData{
|
||||||
Data: template.HTML(strings.ReplaceAll(err.Error(), "\n", "<br>")),
|
Data: template.HTML(strings.ReplaceAll(err.Error(), "\n", "<br>")),
|
||||||
|
|
@ -225,7 +221,6 @@ func indexHandler(ctx *Context) {
|
||||||
ctx.Status(http.StatusInternalServerError)
|
ctx.Status(http.StatusInternalServerError)
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
return
|
return
|
||||||
case <-time.After(time.Second):
|
|
||||||
}
|
}
|
||||||
ctx.Redirect(p, http.StatusFound)
|
ctx.Redirect(p, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +378,7 @@ func deleteHandler(ctx *Context) {
|
||||||
clean := ctx.Form("clean")
|
clean := ctx.Form("clean")
|
||||||
if clean == "true" {
|
if clean == "true" {
|
||||||
f := fs.Clean(path)
|
f := fs.Clean(path)
|
||||||
id, err := ctx.Srv.DB.DeleteFile(f)
|
id, _, err := ctx.Srv.DB.DeleteFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("db: delete: %s %s", f, err)
|
log.Printf("db: delete: %s %s", f, err)
|
||||||
}
|
}
|
||||||
|
|
@ -405,7 +400,7 @@ func deleteHandler(ctx *Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
id, err := ctx.Srv.DB.DeleteFile(f)
|
id, _, err := ctx.Srv.DB.DeleteFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("db: delete: %s %s", f, err)
|
log.Printf("db: delete: %s %s", f, err)
|
||||||
}
|
}
|
||||||
|
|
@ -581,11 +576,7 @@ func searchHandler(ctx *Context) {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ctx.Srv.DB.GetPaths(res)
|
ctx.Srv.DB.GetPaths(res)
|
||||||
if err != nil {
|
|
||||||
ctx.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data.Data = res
|
ctx.Data.Data = res
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
}
|
}
|
||||||
|
|
@ -693,71 +684,117 @@ func userTotpHandler(ctx *Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logsHandler(ctx *Context) {
|
||||||
|
ctx.Template("logsHandler")
|
||||||
|
ctx.Data = webData{
|
||||||
|
Title: "Scan Logs",
|
||||||
|
BodyTitle: "Scan Logs",
|
||||||
|
}
|
||||||
|
switch ctx.Method() {
|
||||||
|
case "GET":
|
||||||
|
ctx.Data.Data = ctx.Srv.FS.Log.Logs()
|
||||||
|
ctx.Exec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func tagsHandler(ctx *Context) {
|
func tagsHandler(ctx *Context) {
|
||||||
ctx.Template("tagsHandler")
|
ctx.Template("tagsHandler")
|
||||||
ctx.Data = webData{
|
ctx.Data = webData{
|
||||||
Title: "Tags",
|
Title: "Tags",
|
||||||
BodyTitle: "Tags",
|
BodyTitle: "Tags",
|
||||||
}
|
}
|
||||||
t, err := ctx.Srv.DB.GetAllTags()
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data.Data = t
|
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
case "GET":
|
case "GET":
|
||||||
|
t, err := ctx.Srv.DB.GetAllTags()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data.Data = t
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tagsNewHandler(ctx *Context) {
|
||||||
|
ctx.Template("tagsNewHandler")
|
||||||
|
ctx.Data = webData{
|
||||||
|
Title: "New Tag",
|
||||||
|
BodyTitle: "New Tag",
|
||||||
|
}
|
||||||
|
switch ctx.Method() {
|
||||||
|
case "GET":
|
||||||
|
ctx.Data.Data = core.Tag{}
|
||||||
|
ctx.Exec()
|
||||||
|
case "POST":
|
||||||
|
if !ctx.CheckXsrf() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var t core.Tag
|
||||||
|
t.Name = ctx.Form("name")
|
||||||
|
t.Regex = ctx.Form("regex")
|
||||||
|
ctx.Data.Data = t
|
||||||
|
if t.Name == "" {
|
||||||
|
ctx.Error("name cannot be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.Regex == "" {
|
||||||
|
ctx.Error("regex cannot be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := ctx.Srv.DB.NewTag(t.Name, t.Regex); err != nil {
|
||||||
|
ctx.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("tag %s created by: %s\n", t.Name, ctx.User())
|
||||||
|
ctx.Redirect(core.TagsURI, http.StatusFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func tagsEditHandler(ctx *Context) {
|
func tagsEditHandler(ctx *Context) {
|
||||||
ctx.Template("tagsEditHandler")
|
ctx.Template("tagsEditHandler")
|
||||||
ctx.Data = webData{
|
ctx.Data = webData{
|
||||||
Title: "Edit User",
|
Title: "Edit Tag",
|
||||||
BodyTitle: "Edit User",
|
BodyTitle: "Edit Tag",
|
||||||
}
|
}
|
||||||
u, err := ctx.Srv.DB.GetUserWithoutPassword()
|
name := ctx.Var("tag")
|
||||||
if err != nil {
|
|
||||||
ctx.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data.Data = u
|
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
case "GET":
|
case "GET":
|
||||||
|
t, err := ctx.Srv.DB.GetTags(name)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data.Data = t
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
password := ctx.Form("password")
|
var t core.Tag
|
||||||
repeat := ctx.Form("repeat")
|
t.Name = name
|
||||||
|
t.Regex = ctx.Form("regex")
|
||||||
if password != repeat {
|
ctx.Data.Data = t
|
||||||
ctx.Error("passwords do not match")
|
if t.Regex == "" {
|
||||||
|
ctx.Error("regex cannot be empty")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := ctx.Srv.DB.UpdateUserPassword(password); err != nil {
|
if err := ctx.Srv.DB.NewTag(t.Name, t.Regex); err != nil {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("update: %s updated\n", ctx.User())
|
log.Printf("tag %s updated by: %s\n", t.Name, ctx.User())
|
||||||
ctx.Redirect(core.IndexURI, http.StatusFound)
|
ctx.Redirect(core.TagsURI, http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagsDelHandler(ctx *Context) {
|
func tagsDelHandler(ctx *Context) {
|
||||||
ctx.Template("tagsDelHandler")
|
ctx.Template("tagsDelHandler")
|
||||||
ctx.Data = webData{
|
ctx.Data = webData{
|
||||||
Title: "Edit User",
|
Title: "Delete Tag",
|
||||||
BodyTitle: "Edit User",
|
BodyTitle: "Delete Tag",
|
||||||
}
|
}
|
||||||
u, err := ctx.Srv.DB.GetUserWithoutPassword()
|
name := ctx.Var("tag")
|
||||||
if err != nil {
|
ctx.Data.Data = name
|
||||||
ctx.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data.Data = u
|
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
case "GET":
|
case "GET":
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
|
|
@ -765,19 +802,12 @@ func tagsDelHandler(ctx *Context) {
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
password := ctx.Form("password")
|
if err := ctx.Srv.DB.DeleteTag(name); err != nil {
|
||||||
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)
|
ctx.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("update: %s updated\n", ctx.User())
|
log.Printf("tag %s deleted by: %s\n", name, ctx.User())
|
||||||
ctx.Redirect(core.IndexURI, http.StatusFound)
|
ctx.Redirect(core.TagsURI, http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,21 +123,35 @@ var routes = append(static, []route{
|
||||||
[]string{"GET", "POST"},
|
[]string{"GET", "POST"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/tags",
|
core.LogsURI,
|
||||||
|
jwtHandler(
|
||||||
|
authHandler(
|
||||||
|
logsHandler)),
|
||||||
|
[]string{"GET"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
core.TagsURI,
|
||||||
jwtHandler(
|
jwtHandler(
|
||||||
authHandler(
|
authHandler(
|
||||||
tagsHandler)),
|
tagsHandler)),
|
||||||
[]string{"GET"},
|
[]string{"GET"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/tags/{tag:[a-zA-Z0-9]+}/edit",
|
"/tags/new",
|
||||||
|
jwtHandler(
|
||||||
|
authHandler(
|
||||||
|
tagsNewHandler)),
|
||||||
|
[]string{"GET", "POST"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"/tags/edit/{tag:[a-zA-Z0-9]+}",
|
||||||
jwtHandler(
|
jwtHandler(
|
||||||
authHandler(
|
authHandler(
|
||||||
tagsEditHandler)),
|
tagsEditHandler)),
|
||||||
[]string{"GET", "POST"},
|
[]string{"GET", "POST"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/tags/{tag:[a-zA-Z0-9]+}/del",
|
"/tags/del/{tag:[a-zA-Z0-9]+}",
|
||||||
jwtHandler(
|
jwtHandler(
|
||||||
authHandler(
|
authHandler(
|
||||||
tagsDelHandler)),
|
tagsDelHandler)),
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ const (
|
||||||
<tr>
|
<tr>
|
||||||
<th>Path</th>
|
<th>Path</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
|
<th>Tags</th>
|
||||||
<th>Options</th>
|
<th>Options</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -69,6 +70,7 @@ const (
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
||||||
<td>Directory</td>
|
<td>Directory</td>
|
||||||
|
<td></td>
|
||||||
<td><div class="btn-group">
|
<td><div class="btn-group">
|
||||||
<a href="/move{{$item.Abs}}" class="btn btn-sm btn-primary">Move</a>
|
<a href="/move{{$item.Abs}}" class="btn btn-sm btn-primary">Move</a>
|
||||||
<a href="/delete{{$item.Abs}}" class="btn btn-sm btn-danger">Delete</a>
|
<a href="/delete{{$item.Abs}}" class="btn btn-sm btn-danger">Delete</a>
|
||||||
|
|
@ -79,6 +81,11 @@ const (
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
||||||
<td>File</td>
|
<td>File</td>
|
||||||
|
<td>
|
||||||
|
{{range $t := $item.Tags}}
|
||||||
|
<code>{{$t}}</code>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
<td><div class="btn-group">
|
<td><div class="btn-group">
|
||||||
{{if $item.Scan}}
|
{{if $item.Scan}}
|
||||||
<a href="#" class="btn btn-sm btn-warning">Scanning</a>
|
<a href="#" class="btn btn-sm btn-warning">Scanning</a>
|
||||||
|
|
@ -160,7 +167,7 @@ const (
|
||||||
<title>DocStore | {{.Title}}</title>
|
<title>DocStore | {{.Title}}</title>
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" integrity="sha256-bgotk/IPq4Yvt6s8AQGPTM5ZjPjQ6rrBRa2EyxpnFSc="></link>
|
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" integrity="sha256-bgotk/IPq4Yvt6s8AQGPTM5ZjPjQ6rrBRa2EyxpnFSc="></link>
|
||||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-3YeveuySvBgp2GItUS8eV1R/9T1zcPMyvw22SyVf8qo="></link>
|
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-3YeveuySvBgp2GItUS8eV1R/9T1zcPMyvw22SyVf8qo="></link>
|
||||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-NLGEBzpF8t2UDEPzWyOYGGP/HWLNb29ar1MdYlwJroQ="></link>
|
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-TjpqFXPvQzoakyE489hpNO1YK+wUAVd/AdwqpNz1gwc="></link>
|
||||||
<meta name="theme-color" content="#375a7f">
|
<meta name="theme-color" content="#375a7f">
|
||||||
<meta name="description" content="{{.Title}}">
|
<meta name="description" content="{{.Title}}">
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -262,19 +269,32 @@ const (
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}`
|
||||||
|
logs = `{{define "body"}}
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="row">
|
||||||
|
<h2>{{.BodyTitle}}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<textarea class="form-control input-sm md-text mono" rows="30" spellcheck="false" autofocus>{{.Data}}</textarea>
|
||||||
|
</div>
|
||||||
{{end}}`
|
{{end}}`
|
||||||
menu = `{{define "menu"}}
|
menu = `{{define "menu"}}
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item"><a class="nav-link" href="/">Root</a></li>
|
<li class="nav-item"><a class="nav-link" href="/">Root</a></li>
|
||||||
{{if .Login}}
|
{{if .Login}}
|
||||||
<li class="nav-item"><a class="nav-link" href="/tags">Tags</a></li>
|
<li class="nav-item"><a class="nav-link" href="/tags">Tags</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/logs">Logs</a></li>
|
||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
{{if .Login}}
|
||||||
<form class="form-inline" method="post" action="/search">
|
<form class="form-inline" method="post" action="/search">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<input type="text" class="form-control mr-sm-2 menu" placeholder="Search" name="search" value="{{.Search}}" autocomplete="off">
|
<input type="text" class="form-control mr-sm-2 menu" placeholder="Search" name="search" value="{{.Search}}" autocomplete="off">
|
||||||
<button class="btn btn-sm btn-info" type="submit">Search</button>
|
<button class="btn btn-sm btn-info" type="submit">Search</button>
|
||||||
</form>
|
</form>
|
||||||
|
{{end}}
|
||||||
<ul class="nav navbar-nav ml-auto">
|
<ul class="nav navbar-nav ml-auto">
|
||||||
{{if .Login}}
|
{{if .Login}}
|
||||||
<li class="nav-item"><a class="nav-link" href="/user/edit">Profile</a></li>
|
<li class="nav-item"><a class="nav-link" href="/user/edit">Profile</a></li>
|
||||||
|
|
@ -327,9 +347,10 @@ const (
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="name">Name</label>
|
<label class="col-form-label" for="name">Name</label>
|
||||||
<input class="form-control input-sm" type="text" id="name" name="name" autocomplete="off" value="{{.Data}}">
|
<input class="form-control input-sm" type="text" id="name" name="name" autocomplete="off" value="{{.Data}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
||||||
|
<a href="/" class="btn btn-sm btn-primary">Back</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -409,7 +430,7 @@ const (
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>File</th>
|
<th>File</th>
|
||||||
<th>Keyword</th>
|
<th>Tags</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -421,7 +442,7 @@ const (
|
||||||
<br><pre class="wrap">{{$item.HTML}}</pre>
|
<br><pre class="wrap">{{$item.HTML}}</pre>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td>{{$item.Keyword}}</td>
|
<td>{{$item.Tags}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
@ -439,17 +460,11 @@ const (
|
||||||
<strong>{{.BodyTitle}}</strong>
|
<strong>{{.BodyTitle}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="form-horizontal" action="/tags/{{.Data.Name}}/edit" method="post">
|
<p>You are about to delete the tag
|
||||||
|
<a href="/tags/edit/{{.Data}}">{{.Data}}</a>.
|
||||||
|
<form class="form-horizontal" action="/tags/del/{{.Data}}" method="post">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<div class="form-group">
|
<button class="btn btn-sm btn-danger" type="submit">Delete</button>
|
||||||
<label class="col-form-label" for="name">Name</label>
|
|
||||||
<input class="form-control input-sm" type="text" id="name" name="name" disabled>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-form-label" for="regex">Regex</label>
|
|
||||||
<input class="form-control input-sm" type="text" id="regex" name="regex" value="{{.Data.Regex}}">
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Update</button>
|
|
||||||
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -459,21 +474,25 @@ const (
|
||||||
{{end}}`
|
{{end}}`
|
||||||
tagsEdit = `{{define "body"}}
|
tagsEdit = `{{define "body"}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-4 offset-4">
|
<div class="col-8 offset-2">
|
||||||
<div class="card border-primary mx-auto">
|
<div class="card border-primary mx-auto">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<strong>{{.BodyTitle}}</strong>
|
<strong>{{.BodyTitle}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="form-horizontal" action="/tags/{{.Data.Name}}/edit" method="post">
|
<div class="alert alert-dismissible alert-primary">
|
||||||
|
<strong>Note</strong> Editing a tag does not update tags already assigned to a document.
|
||||||
|
You need to reindex all documents to avoid false-positive searches.
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" action="/tags/edit/{{.Data.Name}}" method="post">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="name">Name</label>
|
<label class="col-form-label" for="name">Name</label>
|
||||||
<input class="form-control input-sm" type="text" id="name" name="name" disabled>
|
<input class="form-control input-sm" type="text" id="name" name="name" value="{{.Data.Name}}" disabled>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="regex">Regex</label>
|
<label class="col-form-label" for="regex">Regex</label>
|
||||||
<input class="form-control input-sm" type="text" id="regex" name="regex" value="{{.Data.Regex}}">
|
<input class="form-control input-sm mono" type="text" id="regex" name="regex" value="{{.Data.Regex}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Update</button>
|
<button class="btn btn-sm btn-primary" type="submit">Update</button>
|
||||||
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
||||||
|
|
@ -484,6 +503,16 @@ const (
|
||||||
</div>
|
</div>
|
||||||
{{end}}`
|
{{end}}`
|
||||||
tagsList = `{{define "body"}}
|
tagsList = `{{define "body"}}
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="row">
|
||||||
|
<h2>{{.BodyTitle}}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-xs-5">
|
||||||
|
<a class="btn btn-sm btn-primary" href="/tags/new"><b>New Tag</b></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<table class="table table-stripped table-hover">
|
<table class="table table-stripped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -501,8 +530,8 @@ const (
|
||||||
<td>{{$item.Name}}</td>
|
<td>{{$item.Name}}</td>
|
||||||
<td><code>{{printf "%.50s" $item.Regex}}{{if gt $len 50}}...{{end}}</code></td>
|
<td><code>{{printf "%.50s" $item.Regex}}{{if gt $len 50}}...{{end}}</code></td>
|
||||||
<td><div class="btn-group">
|
<td><div class="btn-group">
|
||||||
<a href="/tags/{{$item.Name}}/edit" class="btn btn-sm btn-primary">Edit</a>
|
<a href="/tags/edit/{{$item.Name}}" class="btn btn-sm btn-primary">Edit</a>
|
||||||
<a href="/tags/{{$item.Name}}/del" class="btn btn-sm btn-danger">Delete</a>
|
<a href="/tags/del/{{$item.Name}}" class="btn btn-sm btn-danger">Delete</a>
|
||||||
</div></td>
|
</div></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
@ -510,6 +539,32 @@ const (
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}`
|
||||||
|
tagsNew = `{{define "body"}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-8 offset-2">
|
||||||
|
<div class="card border-primary mx-auto">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>{{.BodyTitle}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form class="form-horizontal" action="/tags/new" method="post">
|
||||||
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-form-label" for="name">Name</label>
|
||||||
|
<input class="form-control input-sm" type="text" id="name" name="name" value="{{.Data.Name}}" autofocus required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-form-label" for="regex">Regex</label>
|
||||||
|
<input class="form-control input-sm mono" type="text" id="regex" name="regex" value="{{.Data.Regex}}" required>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
||||||
|
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}`
|
{{end}}`
|
||||||
upload = `{{define "body"}}
|
upload = `{{define "body"}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
@ -723,6 +778,9 @@ code {
|
||||||
background-color: #444444;
|
background-color: #444444;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
embed {
|
||||||
|
background-color: #999999;
|
||||||
|
}
|
||||||
textarea,input,select {
|
textarea,input,select {
|
||||||
color: #e2e2e2 !important;
|
color: #e2e2e2 !important;
|
||||||
background-color: #444444 !important;
|
background-color: #444444 !important;
|
||||||
|
|
@ -830,8 +888,11 @@ func (s *HTTPServer) loadTemplates() {
|
||||||
s.templ["userTotpHandler"] = parse(index, menu, userTotp)
|
s.templ["userTotpHandler"] = parse(index, menu, userTotp)
|
||||||
// tags
|
// tags
|
||||||
s.templ["tagsHandler"] = parse(index, menu, tagsList)
|
s.templ["tagsHandler"] = parse(index, menu, tagsList)
|
||||||
|
s.templ["tagsNewHandler"] = parse(index, menu, tagsNew)
|
||||||
s.templ["tagsEditHandler"] = parse(index, menu, tagsEdit)
|
s.templ["tagsEditHandler"] = parse(index, menu, tagsEdit)
|
||||||
s.templ["tagsDelHandler"] = parse(index, menu, tagsDel)
|
s.templ["tagsDelHandler"] = parse(index, menu, tagsDel)
|
||||||
|
// logs
|
||||||
|
s.templ["logsHandler"] = parse(index, menu, logs)
|
||||||
|
|
||||||
if fatal {
|
if fatal {
|
||||||
log.Fatal("parse: ", errors.New("parsing templates failed"))
|
log.Fatal("parse: ", errors.New("parsing templates failed"))
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,11 @@ func (s *HTTPServer) loadTemplates() {
|
||||||
s.templ["userTotpHandler"] = parse(index, menu, userTotp)
|
s.templ["userTotpHandler"] = parse(index, menu, userTotp)
|
||||||
// tags
|
// tags
|
||||||
s.templ["tagsHandler"] = parse(index, menu, tagsList)
|
s.templ["tagsHandler"] = parse(index, menu, tagsList)
|
||||||
|
s.templ["tagsNewHandler"] = parse(index, menu, tagsNew)
|
||||||
s.templ["tagsEditHandler"] = parse(index, menu, tagsEdit)
|
s.templ["tagsEditHandler"] = parse(index, menu, tagsEdit)
|
||||||
s.templ["tagsDelHandler"] = parse(index, menu, tagsDel)
|
s.templ["tagsDelHandler"] = parse(index, menu, tagsDel)
|
||||||
|
// logs
|
||||||
|
s.templ["logsHandler"] = parse(index, menu, logs)
|
||||||
|
|
||||||
if fatal {
|
if fatal {
|
||||||
log.Fatal("parse: ", errors.New("parsing templates failed"))
|
log.Fatal("parse: ", errors.New("parsing templates failed"))
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,9 @@ code {
|
||||||
background-color: #444444;
|
background-color: #444444;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
embed {
|
||||||
|
background-color: #999999;
|
||||||
|
}
|
||||||
textarea,input,select {
|
textarea,input,select {
|
||||||
color: #e2e2e2 !important;
|
color: #e2e2e2 !important;
|
||||||
background-color: #444444 !important;
|
background-color: #444444 !important;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Path</th>
|
<th>Path</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
|
<th>Tags</th>
|
||||||
<th>Options</th>
|
<th>Options</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -31,6 +32,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
||||||
<td>Directory</td>
|
<td>Directory</td>
|
||||||
|
<td></td>
|
||||||
<td><div class="btn-group">
|
<td><div class="btn-group">
|
||||||
<a href="/move{{$item.Abs}}" class="btn btn-sm btn-primary">Move</a>
|
<a href="/move{{$item.Abs}}" class="btn btn-sm btn-primary">Move</a>
|
||||||
<a href="/delete{{$item.Abs}}" class="btn btn-sm btn-danger">Delete</a>
|
<a href="/delete{{$item.Abs}}" class="btn btn-sm btn-danger">Delete</a>
|
||||||
|
|
@ -41,6 +43,11 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
||||||
<td>File</td>
|
<td>File</td>
|
||||||
|
<td>
|
||||||
|
{{range $t := $item.Tags}}
|
||||||
|
<code>{{$t}}</code>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
<td><div class="btn-group">
|
<td><div class="btn-group">
|
||||||
{{if $item.Scan}}
|
{{if $item.Scan}}
|
||||||
<a href="#" class="btn btn-sm btn-warning">Scanning</a>
|
<a href="#" class="btn btn-sm btn-warning">Scanning</a>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<title>DocStore | {{.Title}}</title>
|
<title>DocStore | {{.Title}}</title>
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" integrity="sha256-bgotk/IPq4Yvt6s8AQGPTM5ZjPjQ6rrBRa2EyxpnFSc="></link>
|
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" integrity="sha256-bgotk/IPq4Yvt6s8AQGPTM5ZjPjQ6rrBRa2EyxpnFSc="></link>
|
||||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-3YeveuySvBgp2GItUS8eV1R/9T1zcPMyvw22SyVf8qo="></link>
|
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-3YeveuySvBgp2GItUS8eV1R/9T1zcPMyvw22SyVf8qo="></link>
|
||||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-NLGEBzpF8t2UDEPzWyOYGGP/HWLNb29ar1MdYlwJroQ="></link>
|
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-TjpqFXPvQzoakyE489hpNO1YK+wUAVd/AdwqpNz1gwc="></link>
|
||||||
<meta name="theme-color" content="#375a7f">
|
<meta name="theme-color" content="#375a7f">
|
||||||
<meta name="description" content="{{.Title}}">
|
<meta name="description" content="{{.Title}}">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
10
templates/logs.html
Normal file
10
templates/logs.html
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{{define "body"}}
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="row">
|
||||||
|
<h2>{{.BodyTitle}}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<textarea class="form-control input-sm md-text mono" rows="30" spellcheck="false" autofocus>{{.Data}}</textarea>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
@ -3,13 +3,16 @@
|
||||||
<li class="nav-item"><a class="nav-link" href="/">Root</a></li>
|
<li class="nav-item"><a class="nav-link" href="/">Root</a></li>
|
||||||
{{if .Login}}
|
{{if .Login}}
|
||||||
<li class="nav-item"><a class="nav-link" href="/tags">Tags</a></li>
|
<li class="nav-item"><a class="nav-link" href="/tags">Tags</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/logs">Logs</a></li>
|
||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
{{if .Login}}
|
||||||
<form class="form-inline" method="post" action="/search">
|
<form class="form-inline" method="post" action="/search">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<input type="text" class="form-control mr-sm-2 menu" placeholder="Search" name="search" value="{{.Search}}" autocomplete="off">
|
<input type="text" class="form-control mr-sm-2 menu" placeholder="Search" name="search" value="{{.Search}}" autocomplete="off">
|
||||||
<button class="btn btn-sm btn-info" type="submit">Search</button>
|
<button class="btn btn-sm btn-info" type="submit">Search</button>
|
||||||
</form>
|
</form>
|
||||||
|
{{end}}
|
||||||
<ul class="nav navbar-nav ml-auto">
|
<ul class="nav navbar-nav ml-auto">
|
||||||
{{if .Login}}
|
{{if .Login}}
|
||||||
<li class="nav-item"><a class="nav-link" href="/user/edit">Profile</a></li>
|
<li class="nav-item"><a class="nav-link" href="/user/edit">Profile</a></li>
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="name">Name</label>
|
<label class="col-form-label" for="name">Name</label>
|
||||||
<input class="form-control input-sm" type="text" id="name" name="name" autocomplete="off" value="{{.Data}}">
|
<input class="form-control input-sm" type="text" id="name" name="name" autocomplete="off" value="{{.Data}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
||||||
|
<a href="/" class="btn btn-sm btn-primary">Back</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>File</th>
|
<th>File</th>
|
||||||
<th>Keyword</th>
|
<th>Tags</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
<br><pre class="wrap">{{$item.HTML}}</pre>
|
<br><pre class="wrap">{{$item.HTML}}</pre>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td>{{$item.Keyword}}</td>
|
<td>{{$item.Tags}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,11 @@
|
||||||
<strong>{{.BodyTitle}}</strong>
|
<strong>{{.BodyTitle}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="form-horizontal" action="/tags/{{.Data.Name}}/edit" method="post">
|
<p>You are about to delete the tag
|
||||||
|
<a href="/tags/edit/{{.Data}}">{{.Data}}</a>.
|
||||||
|
<form class="form-horizontal" action="/tags/del/{{.Data}}" method="post">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<div class="form-group">
|
<button class="btn btn-sm btn-danger" type="submit">Delete</button>
|
||||||
<label class="col-form-label" for="name">Name</label>
|
|
||||||
<input class="form-control input-sm" type="text" id="name" name="name" disabled>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-form-label" for="regex">Regex</label>
|
|
||||||
<input class="form-control input-sm" type="text" id="regex" name="regex" value="{{.Data.Regex}}">
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Update</button>
|
|
||||||
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,24 @@
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-4 offset-4">
|
<div class="col-8 offset-2">
|
||||||
<div class="card border-primary mx-auto">
|
<div class="card border-primary mx-auto">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<strong>{{.BodyTitle}}</strong>
|
<strong>{{.BodyTitle}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="form-horizontal" action="/tags/{{.Data.Name}}/edit" method="post">
|
<div class="alert alert-dismissible alert-primary">
|
||||||
|
<strong>Note</strong> Editing a tag does not update tags already assigned to a document.
|
||||||
|
You need to reindex all documents to avoid false-positive searches.
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" action="/tags/edit/{{.Data.Name}}" method="post">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="name">Name</label>
|
<label class="col-form-label" for="name">Name</label>
|
||||||
<input class="form-control input-sm" type="text" id="name" name="name" disabled>
|
<input class="form-control input-sm" type="text" id="name" name="name" value="{{.Data.Name}}" disabled>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="regex">Regex</label>
|
<label class="col-form-label" for="regex">Regex</label>
|
||||||
<input class="form-control input-sm" type="text" id="regex" name="regex" value="{{.Data.Regex}}">
|
<input class="form-control input-sm mono" type="text" id="regex" name="regex" value="{{.Data.Regex}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Update</button>
|
<button class="btn btn-sm btn-primary" type="submit">Update</button>
|
||||||
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,14 @@
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="row">
|
||||||
|
<h2>{{.BodyTitle}}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-xs-5">
|
||||||
|
<a class="btn btn-sm btn-primary" href="/tags/new"><b>New Tag</b></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<table class="table table-stripped table-hover">
|
<table class="table table-stripped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -16,8 +26,8 @@
|
||||||
<td>{{$item.Name}}</td>
|
<td>{{$item.Name}}</td>
|
||||||
<td><code>{{printf "%.50s" $item.Regex}}{{if gt $len 50}}...{{end}}</code></td>
|
<td><code>{{printf "%.50s" $item.Regex}}{{if gt $len 50}}...{{end}}</code></td>
|
||||||
<td><div class="btn-group">
|
<td><div class="btn-group">
|
||||||
<a href="/tags/{{$item.Name}}/edit" class="btn btn-sm btn-primary">Edit</a>
|
<a href="/tags/edit/{{$item.Name}}" class="btn btn-sm btn-primary">Edit</a>
|
||||||
<a href="/tags/{{$item.Name}}/del" class="btn btn-sm btn-danger">Delete</a>
|
<a href="/tags/del/{{$item.Name}}" class="btn btn-sm btn-danger">Delete</a>
|
||||||
</div></td>
|
</div></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
||||||
26
templates/tagsNew.html
Normal file
26
templates/tagsNew.html
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{{define "body"}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-8 offset-2">
|
||||||
|
<div class="card border-primary mx-auto">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>{{.BodyTitle}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form class="form-horizontal" action="/tags/new" method="post">
|
||||||
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-form-label" for="name">Name</label>
|
||||||
|
<input class="form-control input-sm" type="text" id="name" name="name" value="{{.Data.Name}}" autofocus required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-form-label" for="regex">Regex</label>
|
||||||
|
<input class="form-control input-sm mono" type="text" id="regex" name="regex" value="{{.Data.Regex}}" required>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
||||||
|
<a href="/tags" class="btn btn-sm btn-primary">Back</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue