mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-30 16:09:12 -06:00
161 lines
4.0 KiB
Go
161 lines
4.0 KiB
Go
package webdav
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"io/fs"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/shroff/phylum/server/internal/api/auth"
|
|
"github.com/shroff/phylum/server/internal/core"
|
|
webdav "github.com/shroff/phylum/server/internal/webdav/impl"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type handler struct {
|
|
app *core.App
|
|
prefix string
|
|
}
|
|
|
|
func SetupHandler(r *gin.RouterGroup, app *core.App) {
|
|
logrus.Info("Setting up WebDAV access at " + r.BasePath())
|
|
handler := &handler{
|
|
app: app,
|
|
prefix: r.BasePath(),
|
|
}
|
|
r.Use(auth.CreateBasicAuthHandler(app))
|
|
r.Handle("OPTIONS", "*path", handler.HandleRequest)
|
|
r.Handle("GET", "*path", handler.HandleRequest)
|
|
r.Handle("PUT", "*path", handler.HandleRequest)
|
|
r.Handle("HEAD", "*path", handler.HandleRequest)
|
|
r.Handle("POST", "*path", handler.HandleRequest)
|
|
r.Handle("DELETE", "*path", handler.HandleRequest)
|
|
r.Handle("MOVE", "*path", handler.HandleRequest)
|
|
r.Handle("COPY", "*path", handler.HandleRequest)
|
|
r.Handle("MKCOL", "*path", handler.HandleRequest)
|
|
r.Handle("PROPFIND", "*path", handler.HandleRequest)
|
|
r.Handle("PROPPATCH", "*path", handler.HandleRequest)
|
|
}
|
|
|
|
func (h *handler) HandleRequest(c *gin.Context) {
|
|
fs := auth.GetFileSystem(c)
|
|
if fs == nil {
|
|
c.AbortWithStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
webdavHandler := webdav.Handler{
|
|
Prefix: h.prefix,
|
|
FileSystem: adapter{fs: fs.(core.FileSystem)},
|
|
LockSystem: webdav.NewMemLS(),
|
|
}
|
|
webdavHandler.ServeHTTP(c.Writer, c.Request)
|
|
}
|
|
|
|
type adapter struct {
|
|
fs core.FileSystem
|
|
}
|
|
|
|
func (a adapter) Stat(ctx context.Context, name string) (core.Resource, error) {
|
|
return a.fs.ResourceByPath(name)
|
|
}
|
|
|
|
func (a adapter) OpenRead(r core.Resource, start, len int64) (io.ReadCloser, error) {
|
|
return a.fs.OpenRead(r, start, len)
|
|
}
|
|
|
|
func (a adapter) ReadDir(r core.Resource) ([]core.Resource, error) {
|
|
return a.fs.ReadDir(r)
|
|
}
|
|
|
|
func (a adapter) OpenWrite(ctx context.Context, name string) (io.WriteCloser, error) {
|
|
resource, err := a.Stat(ctx, name)
|
|
|
|
if err != nil {
|
|
if err == fs.ErrNotExist {
|
|
// Try to create the resource if the parent collection exists
|
|
name = strings.TrimRight(name, "/")
|
|
index := strings.LastIndex(name, "/")
|
|
parentPath := name[0:index]
|
|
parent, err := a.Stat(ctx, parentPath)
|
|
if err != nil {
|
|
return nil, fs.ErrNotExist
|
|
}
|
|
resourceName := name[index+1:]
|
|
resourceId := uuid.New()
|
|
resource, err = a.fs.CreateMemberResource(parent, resourceId, resourceName, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return a.fs.OpenWrite(resource)
|
|
}
|
|
return nil, err
|
|
}
|
|
if resource.IsDir() {
|
|
return nil, errors.New("cannot open collection for write")
|
|
}
|
|
return a.fs.OpenWrite(resource)
|
|
}
|
|
|
|
func (a adapter) RemoveAll(ctx context.Context, name string) error {
|
|
resource, err := a.Stat(ctx, name)
|
|
if err != nil {
|
|
return fs.ErrNotExist
|
|
}
|
|
_, err = a.fs.DeleteRecursive(resource, false)
|
|
return err
|
|
}
|
|
|
|
func (a adapter) Mkdir(ctx context.Context, name string) error {
|
|
if _, err := a.Stat(ctx, name); err == nil {
|
|
return fs.ErrExist
|
|
}
|
|
name = strings.TrimRight(name, "/")
|
|
index := strings.LastIndex(name, "/")
|
|
parentPath := name[0:index]
|
|
parent, err := a.Stat(ctx, parentPath)
|
|
if err != nil {
|
|
return fs.ErrNotExist
|
|
}
|
|
dirName := name[index+1:]
|
|
_, err = a.fs.CreateMemberResource(parent, uuid.New(), dirName, true)
|
|
return err
|
|
}
|
|
|
|
func (a adapter) Rename(ctx context.Context, oldName, newName string) error {
|
|
src, err := a.Stat(ctx, oldName)
|
|
if err != nil {
|
|
return fs.ErrNotExist
|
|
}
|
|
|
|
_, err = a.Stat(ctx, newName)
|
|
if err == nil {
|
|
return fs.ErrExist
|
|
}
|
|
|
|
newName = strings.TrimRight(newName, "/")
|
|
index := strings.LastIndex(newName, "/")
|
|
parentPath := newName[0:index]
|
|
parent, err := a.Stat(ctx, parentPath)
|
|
newName = newName[index+1:]
|
|
|
|
if err != nil {
|
|
return fs.ErrNotExist
|
|
}
|
|
|
|
if *src.ParentID() != parent.ID() {
|
|
if _, err = a.fs.UpdateParent(src, parent.ID()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if src.Name() != newName && newName != "" && newName != "/" {
|
|
if _, err = a.fs.UpdateName(src, newName); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|