basic functions working
This commit is contained in:
parent
abc6159044
commit
ffeeae5702
22 changed files with 420 additions and 129 deletions
|
|
@ -10,6 +10,8 @@ var (
|
|||
|
||||
RawPrefix = "/raw"
|
||||
IndexPrefix = "/index"
|
||||
UploadPrefix = "/upload"
|
||||
NewPrefix = "/new"
|
||||
MovePrefix = "/move"
|
||||
DeletePrefix = "/delete"
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ type Result struct {
|
|||
type Path struct {
|
||||
Name string
|
||||
Abs string
|
||||
Indexed bool
|
||||
Flag bool
|
||||
}
|
||||
|
||||
type Paths []Path
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func (db *DB) GetPaths(res []core.Result) error {
|
|||
|
||||
func (db *DB) GetIndexed(p core.Paths) {
|
||||
for i, v := range p {
|
||||
p[i].Indexed = db.IsIndexed(v.Abs)
|
||||
p[i].Flag = db.IsIndexed(v.Abs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,22 @@ package fs
|
|||
import (
|
||||
"errors"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/core"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
Undefined Mode = iota
|
||||
IsDir
|
||||
IsFile
|
||||
)
|
||||
|
||||
func (fs *Filesystem) GetFile(path string) (f *os.File, fi os.FileInfo, err error) {
|
||||
path = strings.TrimPrefix(filepath.Clean(path), core.RawPrefix)
|
||||
path = strings.TrimPrefix(Clean(path), core.RawPrefix)
|
||||
p := filepath.Join(fs.Base, path)
|
||||
f, err = os.Open(p)
|
||||
if err != nil {
|
||||
|
|
@ -25,8 +34,8 @@ func (fs *Filesystem) GetFile(path string) (f *os.File, fi os.FileInfo, err erro
|
|||
return
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Mode(path string) (mode FileMode, err error) {
|
||||
path = filepath.Clean(path)
|
||||
func (fs *Filesystem) Mode(path string) (mode Mode, err error) {
|
||||
path = Clean(path)
|
||||
p := filepath.Join(fs.Base, path)
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
|
|
@ -41,17 +50,46 @@ func (fs *Filesystem) Mode(path string) (mode FileMode, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (fs *Filesystem) NewFile(r io.Reader, path, orig, name string) (newfile string, err error) {
|
||||
path = Clean(path)
|
||||
orig = Clean(orig)
|
||||
_, orig = filepath.Split(orig)
|
||||
name = Clean(name)
|
||||
_, name = filepath.Split(name)
|
||||
if name == "" {
|
||||
name = orig
|
||||
}
|
||||
newfile = filepath.Join(path, name)
|
||||
f, err := os.OpenFile(filepath.Join(fs.Base, newfile), os.O_RDWR|os.O_CREATE, FileMode)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, r)
|
||||
return
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Mkdir(path, name string) error {
|
||||
path = Clean(path)
|
||||
name = Clean(name)
|
||||
return os.Mkdir(filepath.Join(fs.Base, path, name), DirMode)
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Move(path, dest, name string) (string, error) {
|
||||
path = filepath.Clean(path)
|
||||
path = Clean(path)
|
||||
if name == "" {
|
||||
_, name = filepath.Split(path)
|
||||
}
|
||||
newfile := filepath.Clean(filepath.Join(dest, name))
|
||||
return newfile, os.Rename(filepath.Join(fs.Base, path), filepath.Join(fs.Base, newfile))
|
||||
fullpath := filepath.Join(fs.Base, path)
|
||||
if fullpath == fs.Base {
|
||||
return "", errors.New("the root path can not be moved")
|
||||
}
|
||||
newfile := Clean(filepath.Join(dest, name))
|
||||
return newfile, os.Rename(fullpath, filepath.Join(fs.Base, newfile))
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Delete(path string) (removed []string, err error) {
|
||||
path = filepath.Clean(path)
|
||||
path = Clean(path)
|
||||
fullpath := filepath.Join(fs.Base, path)
|
||||
if fullpath == fs.Base {
|
||||
return nil, errors.New("the root path can not be deleted")
|
||||
|
|
|
|||
26
pkg/fs/fs.go
26
pkg/fs/fs.go
|
|
@ -9,12 +9,9 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type FileMode int
|
||||
|
||||
const (
|
||||
Undefined FileMode = iota
|
||||
IsDir
|
||||
IsFile
|
||||
DirMode = 0750
|
||||
FileMode = 0640
|
||||
)
|
||||
|
||||
// Directory represents a directory and its contents
|
||||
|
|
@ -40,7 +37,7 @@ func NewFilesystem(base string) (fs *Filesystem, err error) {
|
|||
}
|
||||
|
||||
func (fs *Filesystem) ReadDir(path string) (d *Directory) {
|
||||
path = filepath.Clean(path)
|
||||
path = Clean(path)
|
||||
combined := filepath.Join(fs.Base, path)
|
||||
f, err := os.Open(combined)
|
||||
if err != nil {
|
||||
|
|
@ -70,7 +67,12 @@ func (fs *Filesystem) ReadDir(path string) (d *Directory) {
|
|||
return
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Recursive() (p core.Paths) {
|
||||
func (fs *Filesystem) Recursive(p string) (paths core.Paths) {
|
||||
p = Clean(p)
|
||||
p, _ = filepath.Split(p)
|
||||
if len(p) >= 2 {
|
||||
p = p[:len(p)-1]
|
||||
}
|
||||
filepath.Walk(fs.Base, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
|
|
@ -80,16 +82,16 @@ func (fs *Filesystem) Recursive() (p core.Paths) {
|
|||
if a == "" {
|
||||
a = "/"
|
||||
}
|
||||
p = append(p, core.Path{Abs: a})
|
||||
paths = append(paths, core.Path{Abs: a, Flag: a == p})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
sort.Sort(p)
|
||||
sort.Sort(paths)
|
||||
return
|
||||
}
|
||||
|
||||
func (fs *Filesystem) RecursiveFiles(p string) (files []string) {
|
||||
p = filepath.Clean(p)
|
||||
p = Clean(p)
|
||||
fullpath := filepath.Join(fs.Base, p)
|
||||
filepath.Walk(fullpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
|
|
@ -104,7 +106,7 @@ func (fs *Filesystem) RecursiveFiles(p string) (files []string) {
|
|||
}
|
||||
|
||||
func Paths(path string) (p core.Paths) {
|
||||
path = filepath.Clean(path)
|
||||
path = Clean(path)
|
||||
s := strings.Split(path, string(filepath.Separator))
|
||||
for i, v := range s[1:] {
|
||||
if v == "" {
|
||||
|
|
@ -117,7 +119,7 @@ func Paths(path string) (p core.Paths) {
|
|||
p = append(p, core.Path{Name: v, Abs: filepath.Join(p[i-1].Abs, v)})
|
||||
}
|
||||
if len(p) != 0 {
|
||||
p[len(p)-1].Indexed = true
|
||||
p[len(p)-1].Flag = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
9
pkg/fs/helper.go
Normal file
9
pkg/fs/helper.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package fs
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
const sep = "/"
|
||||
|
||||
func Clean(path string) string {
|
||||
return filepath.FromSlash(filepath.Clean(sep + path))
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/core"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/fs"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/log"
|
||||
"git.giftfish.de/ston1th/godrop/v2"
|
||||
"os"
|
||||
|
|
@ -72,7 +73,7 @@ func New(base string, langs []string, timeout time.Duration) (s *Scanner, err er
|
|||
}
|
||||
|
||||
func (s *Scanner) Scan(file string) (filename, text string, err error) {
|
||||
file = filepath.Clean(file)
|
||||
file = fs.Clean(file)
|
||||
scanfile := filepath.Join(s.base, file)
|
||||
var pdffile string
|
||||
pdf := isPDF(scanfile)
|
||||
|
|
@ -91,7 +92,7 @@ func (s *Scanner) Scan(file string) (filename, text string, err error) {
|
|||
return
|
||||
}
|
||||
pdffile = filepath.Join(s.base, filename)
|
||||
f, err = os.OpenFile(pdffile, os.O_RDWR|os.O_CREATE, 0640)
|
||||
f, err = os.OpenFile(pdffile, os.O_RDWR|os.O_CREATE, fs.FileMode)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"git.giftfish.de/ston1th/jwt/v3"
|
||||
"github.com/gorilla/mux"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
|
@ -27,7 +28,7 @@ func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) *Context
|
|||
h.Set("X-Frame-Options", "sameorigin")
|
||||
h.Set("X-Content-Type-Options", "nosniff")
|
||||
h.Set("X-XSS-Protection", "1; mode=block")
|
||||
h.Set("Content-Security-Policy", "default-src 'none';object-src 'self';frame-src 'self';style-src 'self';img-src 'self' https: data:;connect-src 'self';frame-ancestors 'self'")
|
||||
h.Set("Content-Security-Policy", "default-src 'none';object-src 'self';frame-src 'self';style-src 'self';img-src 'self' data:;connect-src 'self';frame-ancestors 'self'")
|
||||
h.Set("Referrer-Policy", "same-origin")
|
||||
return &Context{
|
||||
Request: r,
|
||||
|
|
@ -202,6 +203,15 @@ func (c *Context) Var(name string) (ret string) {
|
|||
return
|
||||
}
|
||||
|
||||
func (c *Context) File(name string) (io.Reader, string, error) {
|
||||
var filename string
|
||||
f, fh, err := c.Request.FormFile(name)
|
||||
if fh != nil {
|
||||
filename = fh.Filename
|
||||
}
|
||||
return f, filename, err
|
||||
}
|
||||
|
||||
// CheckXsrf validates the xsrf token
|
||||
func (c *Context) CheckXsrf() (ok bool) {
|
||||
ok = checkXsrf(c.Form("token"), c.Token.RawSig()[:keySize])
|
||||
|
|
|
|||
|
|
@ -216,18 +216,85 @@ func indexHandler(ctx *Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func uploadHandler(ctx *Context) {
|
||||
path := strings.TrimPrefix(ctx.Path(), core.UploadPrefix)
|
||||
ctx.Data = webData{
|
||||
Title: "Upload",
|
||||
BodyTitle: "Upload",
|
||||
}
|
||||
ctx.Data.Path = path
|
||||
ctx.Template("uploadHandler")
|
||||
switch ctx.Method() {
|
||||
case "GET":
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
f, orig, err := ctx.File("file")
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
return
|
||||
}
|
||||
newfile, err := ctx.Srv.FS.NewFile(f, path, orig, ctx.Form("name"))
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
return
|
||||
}
|
||||
ctx.Redirect(newfile, http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func newDirHandler(ctx *Context) {
|
||||
path := strings.TrimPrefix(ctx.Path(), core.NewPrefix)
|
||||
ctx.Data = webData{
|
||||
Title: "Create Directory",
|
||||
BodyTitle: "Create Directory",
|
||||
}
|
||||
ctx.Data.Path = path
|
||||
ctx.Template("newDirHandler")
|
||||
switch ctx.Method() {
|
||||
case "GET":
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
err := ctx.Srv.FS.Mkdir(path, ctx.Form("name"))
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
return
|
||||
}
|
||||
ctx.Redirect(path, http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func moveHandler(ctx *Context) {
|
||||
path := strings.TrimPrefix(ctx.Path(), core.MovePrefix)
|
||||
mode, err := ctx.Srv.FS.Mode(path)
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
return
|
||||
}
|
||||
switch mode {
|
||||
case fs.IsFile:
|
||||
ctx.Data = webData{
|
||||
Title: "Move File",
|
||||
BodyTitle: "Move File",
|
||||
}
|
||||
case fs.IsDir:
|
||||
ctx.Data = webData{
|
||||
Title: "Move Directory",
|
||||
BodyTitle: "Move Directory",
|
||||
}
|
||||
default:
|
||||
ctx.Data = webData{
|
||||
Title: "Move",
|
||||
BodyTitle: "Move",
|
||||
}
|
||||
ctx.Error(noSuchFile)
|
||||
return
|
||||
}
|
||||
ctx.Data.Path = path
|
||||
ctx.Data.Paths = ctx.Srv.FS.Recursive(path)
|
||||
_, ctx.Data.Data = filepath.Split(path)
|
||||
ctx.Template("moveHandler")
|
||||
switch ctx.Method() {
|
||||
case "GET":
|
||||
ctx.Data.Path = path
|
||||
ctx.Data.Paths = ctx.Srv.FS.Recursive()
|
||||
_, ctx.Data.Data = filepath.Split(path)
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
name := ctx.Form("name")
|
||||
|
|
@ -320,6 +387,7 @@ func dirHandler(ctx *Context) {
|
|||
}
|
||||
dir := ctx.Srv.FS.ReadDir(path)
|
||||
ctx.Srv.DB.GetIndexed(dir.Files)
|
||||
ctx.Data.Path = path
|
||||
ctx.Data.Data = dir
|
||||
ctx.Data.Paths = fs.Paths(path)
|
||||
ctx.Exec()
|
||||
|
|
@ -328,11 +396,14 @@ func dirHandler(ctx *Context) {
|
|||
Title: "Document Viewer",
|
||||
}
|
||||
ctx.Template("fileHandler")
|
||||
ctx.Data.Data = core.RawPrefix + path
|
||||
ctx.Data.Data = core.Path{
|
||||
Name: path,
|
||||
Abs: core.RawPrefix + path,
|
||||
Flag: ctx.Srv.DB.IsIndexed(path),
|
||||
}
|
||||
ctx.Data.Paths = fs.Paths(path)
|
||||
ctx.Exec()
|
||||
}
|
||||
case "POST":
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,20 @@ var prefixRoutes = []route{
|
|||
indexHandler)),
|
||||
[]string{"GET", "POST"},
|
||||
},
|
||||
{
|
||||
core.UploadPrefix,
|
||||
jwtHandler(
|
||||
authHandler(
|
||||
uploadHandler)),
|
||||
[]string{"GET", "POST"},
|
||||
},
|
||||
{
|
||||
core.NewPrefix,
|
||||
jwtHandler(
|
||||
authHandler(
|
||||
newDirHandler)),
|
||||
[]string{"GET", "POST"},
|
||||
},
|
||||
{
|
||||
core.MovePrefix,
|
||||
jwtHandler(
|
||||
|
|
@ -69,7 +83,7 @@ var prefixRoutes = []route{
|
|||
jwtHandler(
|
||||
authHandler(
|
||||
dirHandler)),
|
||||
[]string{"GET", "POST", "PUT", "DELETE"},
|
||||
[]string{"GET"},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -82,6 +82,8 @@ func (s *HTTPServer) loadTemplates() {
|
|||
|
||||
s.templ["dirHandler"] = parse(index, menu, dir)
|
||||
s.templ["fileHandler"] = parse(index, menu, file)
|
||||
s.templ["uploadHandler"] = parse(index, menu, upload)
|
||||
s.templ["newDirHandler"] = parse(index, menu, newDir)
|
||||
s.templ["moveHandler"] = parse(index, menu, move)
|
||||
s.templ["deleteHandler"] = parse(index, menu, delete)
|
||||
s.templ["notFoundHandler"] = parse(index, menu, notFound)
|
||||
|
|
|
|||
12
templates/bootstrap.css
vendored
12
templates/bootstrap.css
vendored
File diff suppressed because one or more lines are too long
|
|
@ -41,6 +41,9 @@ a.anchor {
|
|||
top: -70px;
|
||||
visibility: hidden;
|
||||
}
|
||||
a.mono {
|
||||
font-family: monospace;
|
||||
}
|
||||
.alert-primary {
|
||||
background-color: #375a7f;
|
||||
border-color: #375a7f;
|
||||
|
|
@ -71,10 +74,6 @@ h5 {
|
|||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
.md-text {
|
||||
font-family: 'Courier New';
|
||||
font-size: 14;
|
||||
}
|
||||
ul.toc {
|
||||
list-style-type: disc;
|
||||
margin-bottom: 0 !important;
|
||||
|
|
@ -119,6 +118,12 @@ input.menu {
|
|||
.menu-search-input {
|
||||
background-color: #2f2f2f !important;
|
||||
}
|
||||
.custom-file-label {
|
||||
background-color: #444 !important;
|
||||
}
|
||||
.custom-file-label::after {
|
||||
color: #fff;
|
||||
}
|
||||
html, body, .container, .content {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
|
@ -132,21 +137,18 @@ html, body, .container, .content {
|
|||
margin-bottom: 20px;
|
||||
width: 250px;
|
||||
}
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
margin: 0 auto -60px;
|
||||
}
|
||||
.push {
|
||||
height: 20px;
|
||||
}
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
.footer-wrapper {
|
||||
.relative {
|
||||
position: relative;
|
||||
padding-top: 20px;
|
||||
height: 50px;
|
||||
color: #888888;
|
||||
}
|
||||
.btn-breadcrumb {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 38%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
|
@ -1,12 +1,20 @@
|
|||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="nav-container full-width relative">
|
||||
<ol class="breadcrumb full-width">
|
||||
<li class="breadcrumb-item"></li>
|
||||
<li class="breadcrumb-item"><a href="/">root</a></li>
|
||||
{{range $item := .Paths}}
|
||||
<li class="breadcrumb-item{{if $item.Indexed}} active{{end}}">{{if $item.Indexed}}{{$item.Name}}{{else}}<a href="{{$item.Abs}}">{{$item.Name}}</a>{{end}}</li>
|
||||
<li class="breadcrumb-item{{if $item.Flag}} active{{end}}">{{if $item.Flag}}{{$item.Name}}{{else}}<a href="{{$item.Abs}}">{{$item.Name}}</a>{{end}}</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
<div class="btn-group btn-breadcrumb">
|
||||
<a href="/upload{{.Path}}" class="btn btn-sm btn-success">Upload</a>
|
||||
<a href="/new{{.Path}}" class="btn btn-sm btn-primary">New Directory</a>
|
||||
<a href="/move{{.Path}}" class="btn btn-sm btn-primary">Move</a>
|
||||
<a href="/delete{{.Path}}" class="btn btn-sm btn-danger">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<table class="table table-stripped table-hover">
|
||||
|
|
@ -18,10 +26,10 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{if .Data.Dirs}}
|
||||
{{if .Data}}
|
||||
{{range $item := .Data.Dirs}}
|
||||
<tr>
|
||||
<td><a href="{{$item.Abs}}">{{$item.Name}}/</a></td>
|
||||
<th><a href="{{$item.Abs}}">{{$item.Name}}/</a></th>
|
||||
<td>Directory</td>
|
||||
<td><div class="btn-group">
|
||||
<a href="/move{{$item.Abs}}" class="btn btn-sm btn-primary">Move</a>
|
||||
|
|
@ -29,15 +37,13 @@
|
|||
</div></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .Data.Files}}
|
||||
{{range $item := .Data.Files}}
|
||||
<tr>
|
||||
<td><a href="{{$item.Abs}}">{{$item.Name}}</a></td>
|
||||
<th><a href="{{$item.Abs}}">{{$item.Name}}</a></th>
|
||||
<td>File</td>
|
||||
<td><div class="btn-group">
|
||||
{{if not $item.Indexed}}
|
||||
<a href="/index{{$item.Abs}}" class="btn btn-sm btn-primary">Index</a>
|
||||
{{if not $item.Flag}}
|
||||
<a href="/index{{$item.Abs}}" class="btn btn-sm btn-success">Index</a>
|
||||
{{end}}
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="nav-container full-width relative">
|
||||
<ol class="breadcrumb full-width">
|
||||
<li class="breadcrumb-item"></li>
|
||||
<li class="breadcrumb-item"><a href="/">root</a></li>
|
||||
{{range $item := .Paths}}
|
||||
<li class="breadcrumb-item{{if $item.Indexed}} active{{end}}">{{if $item.Indexed}}{{$item.Name}}{{else}}<a href="{{$item.Abs}}">{{$item.Name}}</a>{{end}}</li>
|
||||
<li class="breadcrumb-item{{if $item.Flag}} active{{end}}">{{if $item.Flag}}{{$item.Name}}{{else}}<a href="{{$item.Abs}}">{{$item.Name}}</a>{{end}}</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
<div class="btn-group btn-breadcrumb">
|
||||
{{if not .Data.Flag}}
|
||||
<a href="/index{{.Data.Name}}" class="btn btn-sm btn-success">Index</a>
|
||||
{{end}}
|
||||
<a href="/move{{.Data.Name}}" class="btn btn-sm btn-primary">Move</a>
|
||||
<a href="/delete{{.Data.Name}}" class="btn btn-sm btn-danger">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<embed src="{{.Data}}" width="100%" height="700px" toolbar="1" statusbar="1" navpanes="1"></embed>
|
||||
<embed src="{{.Data.Abs}}" width="100%" height="700px" toolbar="1" statusbar="1" navpanes="1"></embed>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
<head>
|
||||
<title>DocStore | {{.Title}}</title>
|
||||
<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-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-iYnSZSZLepCN7vabI6deUcbcw+1UNCmKhXlJ75O+S6Y="></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-L50A9TBaaysKaYOQWW5+H5nHTNLFLH4+F7Au3o4enAM="></link>
|
||||
<meta name="theme-color" content="#375a7f">
|
||||
<meta name="description" content="{{.Title}}">
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
<div class="alert alert-danger msg">
|
||||
<h4>Error!</h4>
|
||||
<p>{{.Data}}</p>
|
||||
<a href="{{.Path}}" class="btn btn-sm btn-primary">Back</a>
|
||||
</div>
|
||||
<a href="{{.Path}}" class="btn btn-sm btn-primary">Back</a>
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<label class="col-form-label" for="destination">Destination</label>
|
||||
<select class="form-control input-sm" id="destination" name="destination" required>
|
||||
{{range $item := .Paths}}
|
||||
<option value="{{$item.Abs}}">{{$item.Abs}}</option>
|
||||
<option value="{{$item.Abs}}"{{if $item.Flag}} selected{{end}}>{{$item.Abs}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
<input class="form-control input-sm" type="text" id="name" name="name" autocomplete="off" value="{{.Data}}">
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary" type="submit">Move</button>
|
||||
<a href="{{.Path}}" class="btn btn-sm btn-primary">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
22
templates/newDir.html
Normal file
22
templates/newDir.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-xs-4 offset-4">
|
||||
<div class="card border-primary mx-auto">
|
||||
<div class="card-header">
|
||||
<strong>{{.BodyTitle}}</strong>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Create new directory in <a href="{{.Path}}">{{.Path}}</a>.</p>
|
||||
<form class="form-horizontal" action="/new{{.Path}}" 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" autocomplete="off" value="{{.Data}}">
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary" type="submit">Create</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<div class="col">
|
||||
{{if .Data}}
|
||||
{{range $item := .Data}}
|
||||
<a href="{{$item.Path}}"><b>{{$item.Path}}</b></a>
|
||||
<a class="mono" href="{{$item.Path}}"><b>{{$item.Path}}</b></a>
|
||||
<pre class="wrap">{{$item.HTML}}</pre><br>
|
||||
{{end}}
|
||||
{{else}}
|
||||
|
|
|
|||
30
templates/upload.html
Normal file
30
templates/upload.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-xs-4 offset-4">
|
||||
<div class="card border-primary mx-auto">
|
||||
<div class="card-header">
|
||||
<strong>{{.BodyTitle}}</strong>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form class="form-horizontal" action="/upload{{.Path}}" method="post" enctype="multipart/form-data">
|
||||
<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" autocomplete="off" value="{{.Data}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="input-group mb-3">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="file" name="file">
|
||||
<label class="custom-file-label" for="file">Choose file</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-success" type="submit">Upload</button>
|
||||
<a href="{{.Path}}" 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