mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-28 04:05:21 +08:00
273 lines
5.9 KiB
Go
273 lines
5.9 KiB
Go
package ctrl
|
|
|
|
import (
|
|
"encoding/json"
|
|
. "github.com/mickael-kerjean/filestash/server/common"
|
|
"github.com/mickael-kerjean/filestash/server/model"
|
|
"io"
|
|
"net/http"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type FileInfo struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Size int64 `json:"size"`
|
|
Time int64 `json:"time"`
|
|
}
|
|
|
|
func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
var files []FileInfo = make([]FileInfo, 0)
|
|
if model.CanRead(&ctx) == false {
|
|
if model.CanUpload(&ctx) == false {
|
|
SendErrorResult(res, NewError("Permission denied", 403))
|
|
return
|
|
}
|
|
SendSuccessResults(res, files)
|
|
return
|
|
}
|
|
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
entries, err := ctx.Backend.Ls(path)
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
f := FileInfo{
|
|
Name: entry.Name(),
|
|
Size: entry.Size(),
|
|
Time: func(t time.Time) int64 {
|
|
return t.UnixNano() / int64(time.Millisecond)
|
|
}(entry.ModTime()),
|
|
Type: func(isDir bool) string {
|
|
if isDir == true {
|
|
return "directory"
|
|
}
|
|
return "file"
|
|
}(entry.IsDir()),
|
|
}
|
|
files = append(files, f)
|
|
}
|
|
|
|
var perms Metadata = Metadata{}
|
|
if obj, ok := ctx.Backend.(interface{ Meta(path string) Metadata }); ok {
|
|
perms = obj.Meta(path)
|
|
}
|
|
|
|
if model.CanEdit(&ctx) == false {
|
|
perms.CanCreateFile = NewBool(false)
|
|
perms.CanCreateDirectory = NewBool(false)
|
|
perms.CanRename = NewBool(false)
|
|
perms.CanMove = NewBool(false)
|
|
perms.CanDelete = NewBool(false)
|
|
}
|
|
if model.CanUpload(&ctx) == false {
|
|
perms.CanCreateDirectory = NewBool(false)
|
|
perms.CanRename = NewBool(false)
|
|
perms.CanMove = NewBool(false)
|
|
perms.CanDelete = NewBool(false)
|
|
}
|
|
if model.CanShare(&ctx) == false {
|
|
perms.CanShare = NewBool(false)
|
|
}
|
|
|
|
etag := func() string {
|
|
tmp := struct {
|
|
Tmp0 interface{}
|
|
Tmp1 interface{}
|
|
}{ files, perms }
|
|
if j, err := json.Marshal(tmp); err == nil {
|
|
return Hash(string(j))
|
|
}
|
|
return ""
|
|
}()
|
|
if etag != "" && req.Header.Get("If-None-Match") == etag {
|
|
res.WriteHeader(http.StatusNotModified)
|
|
return
|
|
}
|
|
res.Header().Set("Etag", etag)
|
|
|
|
SendSuccessResultsWithMetadata(res, files, perms)
|
|
}
|
|
|
|
func FileCat(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
http.SetCookie(res, &http.Cookie{
|
|
Name: "download",
|
|
Value: "",
|
|
MaxAge: -1,
|
|
Path: "/",
|
|
})
|
|
if model.CanRead(&ctx) == false {
|
|
SendErrorResult(res, ErrPermissionDenied)
|
|
return
|
|
}
|
|
|
|
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
file, err := ctx.Backend.Cat(path)
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
if obj, ok := file.(interface{ Close() error }); ok {
|
|
defer obj.Close()
|
|
}
|
|
|
|
mType := GetMimeType(req.URL.Query().Get("path"))
|
|
res.Header().Set("Content-Type", mType)
|
|
|
|
for _, obj := range Hooks.Get.ProcessFileContentBeforeSend() {
|
|
if file, err = obj(file, &ctx, &res, req); err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
}
|
|
io.Copy(res, file)
|
|
}
|
|
|
|
func FileSave(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
if model.CanEdit(&ctx) == false {
|
|
SendErrorResult(res, NewError("Permission denied", 403))
|
|
return
|
|
}
|
|
|
|
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
file, _, err := req.FormFile("file")
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
err = ctx.Backend.Save(path, file)
|
|
if obj, ok := file.(interface{ Close() error }); ok {
|
|
obj.Close()
|
|
}
|
|
if err != nil {
|
|
SendErrorResult(res, NewError(err.Error(), 403))
|
|
return
|
|
}
|
|
SendSuccessResult(res, nil)
|
|
}
|
|
|
|
func FileMv(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
if model.CanEdit(&ctx) == false {
|
|
SendErrorResult(res, NewError("Permission denied", 403))
|
|
return
|
|
}
|
|
|
|
from, err := pathBuilder(ctx, req.URL.Query().Get("from"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
to, err := pathBuilder(ctx, req.URL.Query().Get("to"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
if from == "" || to == "" {
|
|
SendErrorResult(res, NewError("missing path parameter", 400))
|
|
return
|
|
}
|
|
|
|
err = ctx.Backend.Mv(from, to)
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
SendSuccessResult(res, nil)
|
|
}
|
|
|
|
func FileRm(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
if model.CanEdit(&ctx) == false {
|
|
SendErrorResult(res, NewError("Permission denied", 403))
|
|
return
|
|
}
|
|
|
|
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
err = ctx.Backend.Rm(path)
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
SendSuccessResult(res, nil)
|
|
}
|
|
|
|
func FileMkdir(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
if model.CanUpload(&ctx) == false {
|
|
SendErrorResult(res, NewError("Permission denied", 403))
|
|
return
|
|
}
|
|
|
|
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
err = ctx.Backend.Mkdir(path)
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
SendSuccessResult(res, nil)
|
|
}
|
|
|
|
func FileTouch(ctx App, res http.ResponseWriter, req *http.Request) {
|
|
if model.CanUpload(&ctx) == false {
|
|
SendErrorResult(res, NewError("Permission denied", 403))
|
|
return
|
|
}
|
|
|
|
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
|
|
err = ctx.Backend.Touch(path)
|
|
if err != nil {
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
SendSuccessResult(res, nil)
|
|
}
|
|
|
|
func pathBuilder(ctx App, path string) (string, error) {
|
|
if path == "" {
|
|
return "", NewError("No path available", 400)
|
|
}
|
|
basePath := ctx.Session["path"]
|
|
basePath = filepath.Join(basePath, path)
|
|
if string(path[len(path)-1]) == "/" && basePath != "/" {
|
|
basePath += "/"
|
|
}
|
|
if strings.HasPrefix(basePath, ctx.Session["path"]) == false {
|
|
return "", NewError("There's nothing here", 403)
|
|
}
|
|
return basePath, nil
|
|
}
|