mirror of
https://github.com/schollz/cowyo.git
synced 2023-08-10 21:13:00 +03:00
Add "/uploads" to list all uploaded files
This commit is contained in:
parent
df406ec71b
commit
fc3030339f
59
handlers.go
59
handlers.go
@ -57,6 +57,10 @@ func serve(
|
||||
|
||||
router := gin.Default()
|
||||
|
||||
router.SetFuncMap(template.FuncMap{
|
||||
"sniffContentType": sniffContentType,
|
||||
})
|
||||
|
||||
if hotTemplateReloading {
|
||||
router.LoadHTMLGlob("templates/*.tmpl")
|
||||
} else {
|
||||
@ -307,23 +311,34 @@ func handlePageRequest(c *gin.Context) {
|
||||
c.Data(http.StatusOK, contentType(filename), data)
|
||||
return
|
||||
} else if page == "uploads" {
|
||||
pathname := path.Join(pathToData, command[1:]+".upload")
|
||||
|
||||
if allowInsecureHtml {
|
||||
c.Header(
|
||||
"Content-Disposition",
|
||||
`inline; filename="`+c.DefaultQuery("filename", "upload")+`"`,
|
||||
)
|
||||
if len(command) == 0 || command == "/" || command == "/edit" {
|
||||
if !allowFileUploads {
|
||||
c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("Uploads are disabled on this server"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Prevent malicious html uploads by forcing type to plaintext and 'download-instead-of-view'
|
||||
c.Header("Content-Type", "text/plain")
|
||||
c.Header(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="`+c.DefaultQuery("filename", "upload")+`"`,
|
||||
)
|
||||
command = command[1:]
|
||||
if !strings.HasSuffix(command, ".upload") {
|
||||
command = command + ".upload"
|
||||
}
|
||||
pathname := path.Join(pathToData, command)
|
||||
|
||||
if allowInsecureHtml {
|
||||
c.Header(
|
||||
"Content-Disposition",
|
||||
`inline; filename="`+c.DefaultQuery("filename", "upload")+`"`,
|
||||
)
|
||||
} else {
|
||||
// Prevent malicious html uploads by forcing type to plaintext and 'download-instead-of-view'
|
||||
c.Header("Content-Type", "text/plain")
|
||||
c.Header(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="`+c.DefaultQuery("filename", "upload")+`"`,
|
||||
)
|
||||
}
|
||||
c.File(pathname)
|
||||
return
|
||||
}
|
||||
c.File(pathname)
|
||||
return
|
||||
}
|
||||
|
||||
p := Open(page)
|
||||
@ -410,11 +425,20 @@ func handlePageRequest(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var DirectoryEntries []DirectoryEntry
|
||||
var DirectoryEntries []os.FileInfo
|
||||
if page == "ls" {
|
||||
command = "/view"
|
||||
DirectoryEntries = DirectoryList()
|
||||
}
|
||||
if page == "uploads" {
|
||||
command = "/view"
|
||||
var err error
|
||||
DirectoryEntries, err = UploadList()
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// swap out /view for /read if it is published
|
||||
if p.IsPublished {
|
||||
@ -432,7 +456,8 @@ func handlePageRequest(c *gin.Context) {
|
||||
command[0:2] != "/l" &&
|
||||
command[0:2] != "/r" &&
|
||||
command[0:2] != "/h",
|
||||
"DirectoryPage": page == "ls",
|
||||
"DirectoryPage": page == "ls" || page == "uploads",
|
||||
"UploadPage": page == "uploads",
|
||||
"DirectoryEntries": DirectoryEntries,
|
||||
"Page": page,
|
||||
"RenderedPage": template.HTML([]byte(rawHTML)),
|
||||
|
53
page.go
53
page.go
@ -54,7 +54,7 @@ func Open(name string) (p *Page) {
|
||||
}
|
||||
|
||||
type DirectoryEntry struct {
|
||||
Name string
|
||||
Path string
|
||||
Length int
|
||||
Numchanges int
|
||||
LastEdited time.Time
|
||||
@ -64,23 +64,66 @@ func (d DirectoryEntry) LastEditTime() string {
|
||||
return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006")
|
||||
}
|
||||
|
||||
func DirectoryList() []DirectoryEntry {
|
||||
func (d DirectoryEntry) Name() string {
|
||||
return d.Path
|
||||
}
|
||||
|
||||
func (d DirectoryEntry) Size() int64 {
|
||||
return int64(d.Length)
|
||||
}
|
||||
|
||||
func (d DirectoryEntry) Mode() os.FileMode {
|
||||
return os.ModePerm
|
||||
}
|
||||
|
||||
func (d DirectoryEntry) ModTime() time.Time {
|
||||
return d.LastEdited
|
||||
}
|
||||
|
||||
func (d DirectoryEntry) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (d DirectoryEntry) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func DirectoryList() []os.FileInfo {
|
||||
files, _ := ioutil.ReadDir(pathToData)
|
||||
entries := make([]DirectoryEntry, len(files))
|
||||
entries := make([]os.FileInfo, len(files))
|
||||
for i, f := range files {
|
||||
name := DecodeFileName(f.Name())
|
||||
p := Open(name)
|
||||
entries[i] = DirectoryEntry{
|
||||
Name: name,
|
||||
Path: name,
|
||||
Length: len(p.Text.GetCurrent()),
|
||||
Numchanges: p.Text.NumEdits(),
|
||||
LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0),
|
||||
}
|
||||
}
|
||||
sort.Slice(entries, func(i, j int) bool { return entries[i].LastEdited.After(entries[j].LastEdited) })
|
||||
sort.Slice(entries, func(i, j int) bool { return entries[i].ModTime().After(entries[j].ModTime()) })
|
||||
return entries
|
||||
}
|
||||
|
||||
type UploadEntry struct {
|
||||
os.FileInfo
|
||||
}
|
||||
|
||||
func UploadList() ([]os.FileInfo, error) {
|
||||
paths, err := filepath.Glob(path.Join(pathToData, "sha256*"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]os.FileInfo, len(paths))
|
||||
for i := range paths {
|
||||
result[i], err = os.Stat(paths[i])
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func DecodeFileName(s string) string {
|
||||
s2, _ := decodeFromBase32(strings.Split(s, ".")[0])
|
||||
return s2
|
||||
|
@ -202,18 +202,29 @@
|
||||
|
||||
{{ if .DirectoryPage }}
|
||||
<table style="width:100%">
|
||||
{{ $upload := .UploadPage }}
|
||||
<tr>
|
||||
<th>Document</th>
|
||||
<th>Current size</th>
|
||||
{{ if not $upload }}
|
||||
<th>Num Edits</th>
|
||||
{{ end }}
|
||||
<th>Last Edited</th>
|
||||
</tr>
|
||||
{{range .DirectoryEntries}}
|
||||
<tr>
|
||||
<td><a href="/{{ .Name }}/view">{{ .Name }}</a></td>
|
||||
<td>{{.Length}}</td>
|
||||
<td>
|
||||
{{ if $upload }}
|
||||
<a href="/uploads/{{ .Name }}">{{ sniffContentType .Name }}</a>
|
||||
{{ else }}
|
||||
<a href="/{{ .Name }}/view">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td>{{.Size}}</td>
|
||||
{{ if not $upload }}
|
||||
<td>{{.Numchanges}}</td>
|
||||
<td>{{.LastEditTime}}</td>
|
||||
{{ end }}
|
||||
<td>{{.ModTime.Format "Mon Jan 2 15:04:05 MST 2006" }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
|
21
utils.go
21
utils.go
@ -6,7 +6,9 @@ import (
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -92,6 +94,25 @@ func contentType(filename string) string {
|
||||
return "text/html"
|
||||
}
|
||||
|
||||
func sniffContentType(name string) (string, error) {
|
||||
file, err := os.Open(path.Join(pathToData, name))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Only the first 512 bytes are used to sniff the content type.
|
||||
buffer := make([]byte, 512)
|
||||
_, err = file.Read(buffer)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Always returns a valid content-type and "application/octet-stream" if no others seemed to match.
|
||||
return http.DetectContentType(buffer), nil
|
||||
}
|
||||
|
||||
func timeTrack(start time.Time, name string) {
|
||||
elapsed := time.Since(start)
|
||||
log.Debug("%s took %s", name, elapsed)
|
||||
|
Loading…
Reference in New Issue
Block a user