From 0f2425ce5343c374359bd5630a516815cc3cd62d Mon Sep 17 00:00:00 2001 From: Noah Hsu Date: Fri, 2 Sep 2022 18:24:14 +0800 Subject: [PATCH] feat: add teambition driver --- drivers/123/meta.go | 2 +- drivers/aliyundrive/meta.go | 2 +- drivers/aliyundrive/types.go | 4 +- drivers/all.go | 1 + drivers/local/driver.go | 2 +- drivers/onedrive/types.go | 5 +- drivers/pikpak/meta.go | 2 +- drivers/pikpak/types.go | 4 +- drivers/teambition/driver.go | 163 ++++++++++++++++++++++++++ drivers/teambition/meta.go | 27 +++++ drivers/teambition/types.go | 68 +++++++++++ drivers/teambition/util.go | 215 +++++++++++++++++++++++++++++++++++ drivers/template/meta.go | 2 +- drivers/virtual/driver.go | 4 +- internal/aria2/monitor.go | 2 +- internal/driver/item.go | 4 +- internal/fs/get.go | 2 +- internal/model/object.go | 31 ++++- internal/op/fs.go | 4 +- internal/op/storage.go | 2 +- server/handles/fsmanage.go | 2 +- server/webdav/webdav.go | 5 +- 22 files changed, 523 insertions(+), 30 deletions(-) create mode 100644 drivers/teambition/driver.go create mode 100644 drivers/teambition/meta.go create mode 100644 drivers/teambition/types.go create mode 100644 drivers/teambition/util.go diff --git a/drivers/123/meta.go b/drivers/123/meta.go index a4933a1e..e6d9fa10 100644 --- a/drivers/123/meta.go +++ b/drivers/123/meta.go @@ -10,7 +10,7 @@ type Addition struct { Password string `json:"password" required:"true"` OrderBy string `json:"order_by" type:"select" options:"name,fileId,updateAt,createAt" default:"name"` OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"` - driver.RootFolderId + driver.RootFolderID // define other StreamUpload bool `json:"stream_upload"` //Field string `json:"field" type:"select" required:"true" options:"a,b,c" default:"a"` diff --git a/drivers/aliyundrive/meta.go b/drivers/aliyundrive/meta.go index ed17de32..785ebe89 100644 --- a/drivers/aliyundrive/meta.go +++ b/drivers/aliyundrive/meta.go @@ -6,7 +6,7 @@ import ( ) type Addition struct { - driver.RootFolderId + driver.RootFolderID RefreshToken string `json:"refresh_token" required:"true"` OrderBy string `json:"order_by" type:"select" options:"name,size,updated_at,created_at"` OrderDirection string `json:"order_direction" type:"select" options:"ASC,DESC"` diff --git a/drivers/aliyundrive/types.go b/drivers/aliyundrive/types.go index dd1ceade..98934cd4 100644 --- a/drivers/aliyundrive/types.go +++ b/drivers/aliyundrive/types.go @@ -31,8 +31,8 @@ type File struct { Url string `json:"url"` } -func fileToObj(f File) model.ObjectThumbnail { - return model.ObjectThumbnail{ +func fileToObj(f File) *model.ObjThumb { + return &model.ObjThumb{ Object: model.Object{ ID: f.FileId, Name: f.Name, diff --git a/drivers/all.go b/drivers/all.go index a779ae82..318d3d46 100644 --- a/drivers/all.go +++ b/drivers/all.go @@ -6,6 +6,7 @@ import ( _ "github.com/alist-org/alist/v3/drivers/local" _ "github.com/alist-org/alist/v3/drivers/onedrive" _ "github.com/alist-org/alist/v3/drivers/pikpak" + _ "github.com/alist-org/alist/v3/drivers/teambition" _ "github.com/alist-org/alist/v3/drivers/virtual" ) diff --git a/drivers/local/driver.go b/drivers/local/driver.go index ed400b77..585a99e3 100644 --- a/drivers/local/driver.go +++ b/drivers/local/driver.go @@ -78,7 +78,7 @@ func (d *Local) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ thumb = utils.EncodePath(thumb, true) thumb += "?type=thumb" } - file := model.ObjectThumbnail{ + file := model.ObjThumb{ Object: model.Object{ Name: f.Name(), Modified: f.ModTime(), diff --git a/drivers/onedrive/types.go b/drivers/onedrive/types.go index 170d8eaf..8f981d40 100644 --- a/drivers/onedrive/types.go +++ b/drivers/onedrive/types.go @@ -42,12 +42,12 @@ type File struct { } `json:"parentReference"` } -func fileToObj(f File) *model.ObjectThumbnail { +func fileToObj(f File) *model.ObjThumbURL { thumb := "" if len(f.Thumbnails) > 0 { thumb = f.Thumbnails[0].Medium.Url } - return &model.ObjectThumbnail{ + return &model.ObjThumbURL{ Object: model.Object{ //ID: f.Id, Name: f.Name, @@ -56,6 +56,7 @@ func fileToObj(f File) *model.ObjectThumbnail { IsFolder: f.File == nil, }, Thumbnail: model.Thumbnail{Thumbnail: thumb}, + Url: model.Url{Url: f.Url}, } } diff --git a/drivers/pikpak/meta.go b/drivers/pikpak/meta.go index 88427b95..1e8ea4d8 100644 --- a/drivers/pikpak/meta.go +++ b/drivers/pikpak/meta.go @@ -6,7 +6,7 @@ import ( ) type Addition struct { - driver.RootFolderId + driver.RootFolderID Username string `json:"username" required:"true"` Password string `json:"password" required:"true"` } diff --git a/drivers/pikpak/types.go b/drivers/pikpak/types.go index d469f30a..aa534d89 100644 --- a/drivers/pikpak/types.go +++ b/drivers/pikpak/types.go @@ -28,9 +28,9 @@ type File struct { Medias []Media `json:"medias"` } -func fileToObj(f File) model.ObjectThumbnail { +func fileToObj(f File) *model.ObjThumb { size, _ := strconv.ParseInt(f.Size, 10, 64) - return model.ObjectThumbnail{ + return &model.ObjThumb{ Object: model.Object{ ID: f.Id, Name: f.Name, diff --git a/drivers/teambition/driver.go b/drivers/teambition/driver.go new file mode 100644 index 00000000..90dc3168 --- /dev/null +++ b/drivers/teambition/driver.go @@ -0,0 +1,163 @@ +package teambition + +import ( + "context" + "errors" + "net/http" + + "github.com/alist-org/alist/v3/drivers/base" + "github.com/alist-org/alist/v3/internal/driver" + "github.com/alist-org/alist/v3/internal/errs" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/utils" + "github.com/go-resty/resty/v2" +) + +type Teambition struct { + model.Storage + Addition +} + +func (d *Teambition) Config() driver.Config { + return config +} + +func (d *Teambition) GetAddition() driver.Additional { + return d.Addition +} + +func (d *Teambition) Init(ctx context.Context, storage model.Storage) error { + d.Storage = storage + err := utils.Json.UnmarshalFromString(d.Storage.Addition, &d.Addition) + if err != nil { + return err + } + _, err = d.request("/api/v2/roles", http.MethodGet, nil, nil) + return err +} + +func (d *Teambition) Drop(ctx context.Context) error { + return nil +} + +func (d *Teambition) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { + return d.getFiles(dir.GetID()) +} + +//func (d *Teambition) Get(ctx context.Context, path string) (model.Obj, error) { +// // TODO this is optional +// return nil, errs.NotImplement +//} + +func (d *Teambition) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { + if u, ok := file.(model.URL); ok { + url := u.URL() + res, _ := base.NoRedirectClient.R().Get(url) + if res.StatusCode() == 302 { + url = res.Header().Get("location") + } + return &model.Link{URL: url}, nil + } + return nil, errors.New("can't convert obj to URL") +} + +func (d *Teambition) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { + data := base.Json{ + "objectType": "collection", + "_projectId": d.ProjectID, + "_creatorId": "", + "created": "", + "updated": "", + "title": dirName, + "color": "blue", + "description": "", + "workCount": 0, + "collectionType": "", + "recentWorks": []interface{}{}, + "_parentId": parentDir.GetID(), + "subCount": nil, + } + _, err := d.request("/api/collections", http.MethodPost, func(req *resty.Request) { + req.SetBody(data) + }, nil) + return err +} + +func (d *Teambition) Move(ctx context.Context, srcObj, dstDir model.Obj) error { + pre := "/api/works/" + if srcObj.IsDir() { + pre = "/api/collections/" + } + _, err := d.request(pre+srcObj.GetID()+"/move", http.MethodPut, func(req *resty.Request) { + req.SetBody(base.Json{ + "_parentId": dstDir.GetID(), + }) + }, nil) + return err +} + +func (d *Teambition) Rename(ctx context.Context, srcObj model.Obj, newName string) error { + pre := "/api/works/" + data := base.Json{ + "fileName": newName, + } + if srcObj.IsDir() { + pre = "/api/collections/" + data = base.Json{ + "title": newName, + } + } + _, err := d.request(pre+srcObj.GetID(), http.MethodPut, func(req *resty.Request) { + req.SetBody(data) + }, nil) + return err +} + +func (d *Teambition) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { + pre := "/api/works/" + if srcObj.IsDir() { + pre = "/api/collections/" + } + _, err := d.request(pre+srcObj.GetID()+"/fork", http.MethodPut, func(req *resty.Request) { + req.SetBody(base.Json{ + "_parentId": dstDir.GetID(), + }) + }, nil) + return err +} + +func (d *Teambition) Remove(ctx context.Context, obj model.Obj) error { + pre := "/api/works/" + if obj.IsDir() { + pre = "/api/collections/" + } + _, err := d.request(pre+obj.GetID()+"/archive", http.MethodPost, nil, nil) + return err +} + +func (d *Teambition) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { + res, err := d.request("/projects", http.MethodGet, nil, nil) + if err != nil { + return err + } + token := GetBetweenStr(string(res), "strikerAuth":"", "","phoneForLogin") + var newFile *FileUpload + if stream.GetSize() <= 20971520 { + // post upload + newFile, err = d.upload(stream, token) + } else { + // chunk upload + //err = base.ErrNotImplement + newFile, err = d.chunkUpload(stream, token) + } + if err != nil { + return err + } + return d.finishUpload(newFile, dstDir.GetID()) +} + +func (d *Teambition) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { + return nil, errs.NotSupport +} + +var _ driver.Driver = (*Teambition)(nil) diff --git a/drivers/teambition/meta.go b/drivers/teambition/meta.go new file mode 100644 index 00000000..79d4ec28 --- /dev/null +++ b/drivers/teambition/meta.go @@ -0,0 +1,27 @@ +package teambition + +import ( + "github.com/alist-org/alist/v3/internal/driver" + "github.com/alist-org/alist/v3/internal/op" +) + +type Addition struct { + Region string `json:"region" type:"select" options:"china,international" required:"true"` + Cookie string `json:"cookie" required:"true"` + ProjectID string `json:"project_id" required:"true"` + driver.RootFolderID + OrderBy string `json:"order_by" type:"select" options:"fileName,fileSize,updated,created" default:"fileName"` + OrderDirection string `json:"order_direction" type:"select" options:"Asc,Desc" default:"Asc"` +} + +var config = driver.Config{ + Name: "Teambition", +} + +func New() driver.Driver { + return &Teambition{} +} + +func init() { + op.RegisterDriver(config, New) +} diff --git a/drivers/teambition/types.go b/drivers/teambition/types.go new file mode 100644 index 00000000..330af85b --- /dev/null +++ b/drivers/teambition/types.go @@ -0,0 +1,68 @@ +package teambition + +import "time" + +type ErrResp struct { + Name string `json:"name"` + Message string `json:"message"` +} + +type Collection struct { + ID string `json:"_id"` + Title string `json:"title"` + Updated time.Time `json:"updated"` +} + +type Work struct { + ID string `json:"_id"` + FileName string `json:"fileName"` + FileSize int64 `json:"fileSize"` + FileKey string `json:"fileKey"` + FileCategory string `json:"fileCategory"` + DownloadURL string `json:"downloadUrl"` + ThumbnailURL string `json:"thumbnailUrl"` + Thumbnail string `json:"thumbnail"` + Updated time.Time `json:"updated"` + PreviewURL string `json:"previewUrl"` +} + +type FileUpload struct { + FileKey string `json:"fileKey"` + FileName string `json:"fileName"` + FileType string `json:"fileType"` + FileSize int `json:"fileSize"` + FileCategory string `json:"fileCategory"` + ImageWidth int `json:"imageWidth"` + ImageHeight int `json:"imageHeight"` + InvolveMembers []interface{} `json:"involveMembers"` + Source string `json:"source"` + Visible string `json:"visible"` + ParentId string `json:"_parentId"` +} + +type ChunkUpload struct { + FileUpload + Storage string `json:"storage"` + MimeType string `json:"mimeType"` + Chunks int `json:"chunks"` + ChunkSize int `json:"chunkSize"` + Created time.Time `json:"created"` + FileMD5 string `json:"fileMD5"` + LastUpdated time.Time `json:"lastUpdated"` + UploadedChunks []interface{} `json:"uploadedChunks"` + Token struct { + AppID string `json:"AppID"` + OrganizationID string `json:"OrganizationID"` + UserID string `json:"UserID"` + Exp time.Time `json:"Exp"` + Storage string `json:"Storage"` + Resource string `json:"Resource"` + Speed int `json:"Speed"` + } `json:"token"` + DownloadUrl string `json:"downloadUrl"` + ThumbnailUrl string `json:"thumbnailUrl"` + PreviewUrl string `json:"previewUrl"` + ImmPreviewUrl string `json:"immPreviewUrl"` + PreviewExt string `json:"previewExt"` + LastUploadTime interface{} `json:"lastUploadTime"` +} diff --git a/drivers/teambition/util.go b/drivers/teambition/util.go new file mode 100644 index 00000000..45bc9d9b --- /dev/null +++ b/drivers/teambition/util.go @@ -0,0 +1,215 @@ +package teambition + +import ( + "errors" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/alist-org/alist/v3/drivers/base" + "github.com/alist-org/alist/v3/internal/model" + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +// do others that not defined in Driver interface + +func (d *Teambition) isInternational() bool { + return d.Region == "international" +} + +func (d *Teambition) request(pathname string, method string, callback func(req *resty.Request), resp interface{}) ([]byte, error) { + url := "https://www.teambition.com" + pathname + if d.isInternational() { + url = "https://us.teambition.com" + pathname + } + req := base.RestyClient.R() + req.SetHeader("Cookie", d.Cookie) + if callback != nil { + callback(req) + } + if resp != nil { + req.SetResult(resp) + } + var e ErrResp + req.SetError(&e) + res, err := req.Execute(method, url) + if err != nil { + return nil, err + } + if e.Name != "" { + return nil, errors.New(e.Message) + } + return res.Body(), nil +} + +func (d *Teambition) getFiles(parentId string) ([]model.Obj, error) { + files := make([]model.Obj, 0) + page := 1 + for { + var collections []Collection + _, err := d.request("/api/collections", http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "_parentId": parentId, + "_projectId": d.ProjectID, + "order": d.OrderBy + d.OrderDirection, + "count": "50", + "page": strconv.Itoa(page), + }) + }, &collections) + if err != nil { + return nil, err + } + if len(collections) == 0 { + break + } + page++ + for _, collection := range collections { + if collection.Title == "" { + continue + } + files = append(files, &model.Object{ + ID: collection.ID, + Name: collection.Title, + IsFolder: true, + Modified: collection.Updated, + }) + } + } + page = 1 + for { + var works []Work + _, err := d.request("/api/works", http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "_parentId": parentId, + "_projectId": d.ProjectID, + "order": d.OrderBy + d.OrderDirection, + "count": "50", + "page": strconv.Itoa(page), + }) + }, &works) + if err != nil { + return nil, err + } + if len(works) == 0 { + break + } + page++ + for _, work := range works { + files = append(files, &model.ObjThumbURL{ + Object: model.Object{ + ID: work.ID, + Name: work.FileName, + Size: work.FileSize, + Modified: work.Updated, + }, + Thumbnail: model.Thumbnail{Thumbnail: work.Thumbnail}, + Url: model.Url{Url: work.DownloadURL}, + }) + } + } + return files, nil +} + +func (d *Teambition) upload(file model.FileStreamer, token string) (*FileUpload, error) { + prefix := "tcs" + if d.isInternational() { + prefix = "us-tcs" + } + var newFile FileUpload + _, err := base.RestyClient.R().SetResult(&newFile).SetHeader("Authorization", token). + SetMultipartFormData(map[string]string{ + "name": file.GetName(), + "type": file.GetMimetype(), + "size": strconv.FormatInt(file.GetSize(), 10), + //"lastModifiedDate": "", + }).SetMultipartField("file", file.GetName(), file.GetMimetype(), file). + Post(fmt.Sprintf("https://%s.teambition.net/upload", prefix)) + if err != nil { + return nil, err + } + return &newFile, nil +} + +func (d *Teambition) chunkUpload(file model.FileStreamer, token string) (*FileUpload, error) { + prefix := "tcs" + referer := "https://www.teambition.com/" + if d.isInternational() { + prefix = "us-tcs" + referer = "https://us.teambition.com/" + } + var newChunk ChunkUpload + _, err := base.RestyClient.R().SetResult(&newChunk).SetHeader("Authorization", token). + SetBody(base.Json{ + "fileName": file.GetName(), + "fileSize": file.GetSize(), + "lastUpdated": time.Now(), + }).Post(fmt.Sprintf("https://%s.teambition.net/upload/chunk", prefix)) + if err != nil { + return nil, err + } + for i := 0; i < newChunk.Chunks; i++ { + chunkSize := newChunk.ChunkSize + if i == newChunk.Chunks-1 { + chunkSize = int(file.GetSize()) - i*chunkSize + } + log.Debugf("%d : %d", i, chunkSize) + chunkData := make([]byte, chunkSize) + _, err = io.ReadFull(file, chunkData) + if err != nil { + return nil, err + } + u := fmt.Sprintf("https://%s.teambition.net/upload/chunk/%s?chunk=%d&chunks=%d", + prefix, newChunk.FileKey, i+1, newChunk.Chunks) + log.Debugf("url: %s", u) + _, err := base.RestyClient.R().SetHeaders(map[string]string{ + "Authorization": token, + "Content-Type": "application/octet-stream", + "Referer": referer, + }).SetBody(chunkData).Post(u) + if err != nil { + return nil, err + } + if err != nil { + return nil, err + } + } + _, err = base.RestyClient.R().SetHeader("Authorization", token).Post( + fmt.Sprintf("https://%s.teambition.net/upload/chunk/%s", + prefix, newChunk.FileKey)) + if err != nil { + return nil, err + } + return &newChunk.FileUpload, nil +} + +func (d *Teambition) finishUpload(file *FileUpload, parentId string) error { + file.InvolveMembers = []interface{}{} + file.Visible = "members" + file.ParentId = parentId + _, err := d.request("/api/works", http.MethodPost, func(req *resty.Request) { + req.SetBody(base.Json{ + "works": []FileUpload{*file}, + "_parentId": parentId, + }) + }, nil) + return err +} + +func GetBetweenStr(str, start, end string) string { + n := strings.Index(str, start) + if n == -1 { + return "" + } + n = n + len(start) + str = string([]byte(str)[n:]) + m := strings.Index(str, end) + if m == -1 { + return "" + } + str = string([]byte(str)[:m]) + return str +} diff --git a/drivers/template/meta.go b/drivers/template/meta.go index f3a66184..ca0c8c19 100644 --- a/drivers/template/meta.go +++ b/drivers/template/meta.go @@ -8,7 +8,7 @@ import ( type Addition struct { // Usually one of two driver.RootFolderPath - driver.RootFolderId + driver.RootFolderID // define other Field string `json:"field" type:"select" required:"true" options:"a,b,c" default:"a"` } diff --git a/drivers/virtual/driver.go b/drivers/virtual/driver.go index ec035c38..ce232dfc 100644 --- a/drivers/virtual/driver.go +++ b/drivers/virtual/driver.go @@ -41,7 +41,7 @@ func (d *Virtual) GetAddition() driver.Additional { func (d *Virtual) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { var res []model.Obj for i := 0; i < d.NumFile; i++ { - res = append(res, model.Object{ + res = append(res, &model.Object{ Name: random.String(10), Size: random.RangeInt64(d.MinFileSize, d.MaxFileSize), IsFolder: false, @@ -49,7 +49,7 @@ func (d *Virtual) List(ctx context.Context, dir model.Obj, args model.ListArgs) }) } for i := 0; i < d.NumFolder; i++ { - res = append(res, model.Object{ + res = append(res, &model.Object{ Name: random.String(10), Size: 0, IsFolder: true, diff --git a/internal/aria2/monitor.go b/internal/aria2/monitor.go index 1998b614..4160f8d7 100644 --- a/internal/aria2/monitor.go +++ b/internal/aria2/monitor.go @@ -149,7 +149,7 @@ func (m *Monitor) Complete() error { return errors.Wrapf(err, "failed to open file %s", file.Path) } stream := &model.FileStream{ - Obj: model.Object{ + Obj: &model.Object{ Name: path.Base(file.Path), Size: size, Modified: time.Now(), diff --git a/internal/driver/item.go b/internal/driver/item.go index d39e72b8..f511ecd7 100644 --- a/internal/driver/item.go +++ b/internal/driver/item.go @@ -31,7 +31,7 @@ type RootFolderPath struct { RootFolder string `json:"root_folder" required:"true" help:"Root folder path"` } -type RootFolderId struct { +type RootFolderID struct { RootFolder string `json:"root_folder" required:"true" help:"Root folder id"` } @@ -39,6 +39,6 @@ func (r RootFolderPath) GetRootFolderPath() string { return r.RootFolder } -func (r RootFolderId) GetRootFolderId() string { +func (r RootFolderID) GetRootFolderId() string { return r.RootFolder } diff --git a/internal/fs/get.go b/internal/fs/get.go index fb30e77c..08f0222b 100644 --- a/internal/fs/get.go +++ b/internal/fs/get.go @@ -26,7 +26,7 @@ func get(ctx context.Context, path string) (model.Obj, error) { if err != nil { // if there are no storage prefix with path, maybe root folder if path == "/" { - return model.Object{ + return &model.Object{ Name: "root", Size: 0, Modified: time.Time{}, diff --git a/internal/model/object.go b/internal/model/object.go index dc9816e4..1bc9ba75 100644 --- a/internal/model/object.go +++ b/internal/model/object.go @@ -10,23 +10,23 @@ type Object struct { IsFolder bool } -func (o Object) GetName() string { +func (o *Object) GetName() string { return o.Name } -func (o Object) GetSize() int64 { +func (o *Object) GetSize() int64 { return o.Size } -func (o Object) ModTime() time.Time { +func (o *Object) ModTime() time.Time { return o.Modified } -func (o Object) IsDir() bool { +func (o *Object) IsDir() bool { return o.IsFolder } -func (o Object) GetID() string { +func (o *Object) GetID() string { return o.ID } @@ -38,11 +38,30 @@ type Thumbnail struct { Thumbnail string } +type Url struct { + Url string +} + +func (w Url) URL() string { + return w.Url +} + func (t Thumbnail) Thumb() string { return t.Thumbnail } -type ObjectThumbnail struct { +type ObjThumb struct { Object Thumbnail } + +type ObjectURL struct { + Object + Url +} + +type ObjThumbURL struct { + Object + Thumbnail + Url +} diff --git a/internal/op/fs.go b/internal/op/fs.go index 48066c37..306b1721 100644 --- a/internal/op/fs.go +++ b/internal/op/fs.go @@ -84,7 +84,7 @@ func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, er } // is root folder if r, ok := storage.GetAddition().(driver.IRootFolderId); ok && utils.PathEqual(path, "/") { - return model.Object{ + return &model.Object{ ID: r.GetRootFolderId(), Name: "root", Size: 0, @@ -93,7 +93,7 @@ func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, er }, nil } if r, ok := storage.GetAddition().(driver.IRootFolderPath); ok && isRoot(path, r.GetRootFolderPath()) { - return model.Object{ + return &model.Object{ ID: r.GetRootFolderPath(), Name: "root", Size: 0, diff --git a/internal/op/storage.go b/internal/op/storage.go index 52178482..71d18834 100644 --- a/internal/op/storage.go +++ b/internal/op/storage.go @@ -286,7 +286,7 @@ func GetStorageVirtualFilesByPath(prefix string) []model.Obj { if _, ok := set[name]; ok { continue } - files = append(files, model.Object{ + files = append(files, &model.Object{ Name: name, Size: 0, Modified: v.GetStorage().Modified, diff --git a/server/handles/fsmanage.go b/server/handles/fsmanage.go index f20c6f46..dc56e76c 100644 --- a/server/handles/fsmanage.go +++ b/server/handles/fsmanage.go @@ -220,7 +220,7 @@ func FsPut(c *gin.Context) { return } stream := &model.FileStream{ - Obj: model.Object{ + Obj: &model.Object{ Name: name, Size: size, Modified: time.Now(), diff --git a/server/webdav/webdav.go b/server/webdav/webdav.go index eb7d49d2..ce6acfad 100644 --- a/server/webdav/webdav.go +++ b/server/webdav/webdav.go @@ -296,7 +296,7 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, Modified: time.Now(), } stream := &model.FileStream{ - Obj: obj, + Obj: &obj, ReadCloser: r.Body, Mimetype: r.Header.Get("Content-Type"), } @@ -306,10 +306,9 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, if err != nil { return http.StatusMethodNotAllowed, err } - // TODO clear cache fi, err := fs.Get(ctx, reqPath) if err != nil { - fi = obj + fi = &obj } etag, err := findETag(ctx, h.LockSystem, reqPath, fi) if err != nil {