fix(onedrive): fix Ctime/Mtime (#6397)

pull/6414/head
potoo 2024-05-02 22:27:31 +08:00 committed by GitHub
parent 0e246a7b0c
commit eecea3febd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 10 deletions

View File

@ -118,6 +118,7 @@ func (d *Onedrive) MakeDir(ctx context.Context, parentDir model.Obj, dirName str
"folder": base.Json{}, "folder": base.Json{},
"@microsoft.graph.conflictBehavior": "rename", "@microsoft.graph.conflictBehavior": "rename",
} }
// todo 修复文件夹 ctime/mtime, onedrive 可在 data 里设置 fileSystemInfo 字段, 但是此接口未提供 ctime/mtime
_, err := d.Request(url, http.MethodPost, func(req *resty.Request) { _, err := d.Request(url, http.MethodPost, func(req *resty.Request) {
req.SetBody(data) req.SetBody(data)
}, nil) }, nil)

View File

@ -27,7 +27,7 @@ type File struct {
Id string `json:"id"` Id string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Size int64 `json:"size"` Size int64 `json:"size"`
LastModifiedDateTime time.Time `json:"lastModifiedDateTime"` FileSystemInfo *FileSystemInfoFacet `json:"fileSystemInfo"`
Url string `json:"@microsoft.graph.downloadUrl"` Url string `json:"@microsoft.graph.downloadUrl"`
File *struct { File *struct {
MimeType string `json:"mimeType"` MimeType string `json:"mimeType"`
@ -58,7 +58,7 @@ func fileToObj(f File, parentID string) *Object {
ID: f.Id, ID: f.Id,
Name: f.Name, Name: f.Name,
Size: f.Size, Size: f.Size,
Modified: f.LastModifiedDateTime, Modified: f.FileSystemInfo.LastModifiedDateTime,
IsFolder: f.File == nil, IsFolder: f.File == nil,
}, },
Thumbnail: model.Thumbnail{Thumbnail: thumb}, Thumbnail: model.Thumbnail{Thumbnail: thumb},
@ -72,3 +72,20 @@ type Files struct {
Value []File `json:"value"` Value []File `json:"value"`
NextLink string `json:"@odata.nextLink"` NextLink string `json:"@odata.nextLink"`
} }
// Metadata represents a request to update Metadata.
// It includes only the writeable properties.
// omitempty is intentionally included for all, per https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_update?view=odsp-graph-online#request-body
type Metadata struct {
Description string `json:"description,omitempty"` // Provides a user-visible description of the item. Read-write. Only on OneDrive Personal. Undocumented limit of 1024 characters.
FileSystemInfo *FileSystemInfoFacet `json:"fileSystemInfo,omitempty"` // File system information on client. Read-write.
}
// FileSystemInfoFacet contains properties that are reported by the
// device's local file system for the local version of an item. This
// facet can be used to specify the last modified date or created date
// of the item as it was on the local device.
type FileSystemInfoFacet struct {
CreatedDateTime time.Time `json:"createdDateTime,omitempty"` // The UTC date and time the file was created on a client.
LastModifiedDateTime time.Time `json:"lastModifiedDateTime,omitempty"` // The UTC date and time the file was last modified on a client.
}

View File

@ -127,7 +127,7 @@ func (d *Onedrive) Request(url string, method string, callback base.ReqCallback,
func (d *Onedrive) getFiles(path string) ([]File, error) { func (d *Onedrive) getFiles(path string) ([]File, error) {
var res []File var res []File
nextLink := d.GetMetaUrl(false, path) + "/children?$top=5000&$expand=thumbnails($select=medium)&$select=id,name,size,lastModifiedDateTime,content.downloadUrl,file,parentReference" nextLink := d.GetMetaUrl(false, path) + "/children?$top=5000&$expand=thumbnails($select=medium)&$select=id,name,size,fileSystemInfo,content.downloadUrl,file,parentReference"
for nextLink != "" { for nextLink != "" {
var files Files var files Files
_, err := d.Request(nextLink, http.MethodGet, nil, &files) _, err := d.Request(nextLink, http.MethodGet, nil, &files)
@ -148,7 +148,10 @@ func (d *Onedrive) GetFile(path string) (*File, error) {
} }
func (d *Onedrive) upSmall(ctx context.Context, dstDir model.Obj, stream model.FileStreamer) error { func (d *Onedrive) upSmall(ctx context.Context, dstDir model.Obj, stream model.FileStreamer) error {
url := d.GetMetaUrl(false, stdpath.Join(dstDir.GetPath(), stream.GetName())) + "/content" filepath := stdpath.Join(dstDir.GetPath(), stream.GetName())
// 1. upload new file
// ApiDoc: https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_put_content?view=odsp-graph-online
url := d.GetMetaUrl(false, filepath) + "/content"
data, err := io.ReadAll(stream) data, err := io.ReadAll(stream)
if err != nil { if err != nil {
return err return err
@ -156,12 +159,50 @@ func (d *Onedrive) upSmall(ctx context.Context, dstDir model.Obj, stream model.F
_, err = d.Request(url, http.MethodPut, func(req *resty.Request) { _, err = d.Request(url, http.MethodPut, func(req *resty.Request) {
req.SetBody(data).SetContext(ctx) req.SetBody(data).SetContext(ctx)
}, nil) }, nil)
if err != nil {
return fmt.Errorf("onedrive: Failed to upload new file(path=%v): %w", filepath, err)
}
// 2. update metadata
err = d.updateMetadata(ctx, stream, filepath)
if err != nil {
return fmt.Errorf("onedrive: Failed to update file(path=%v) metadata: %w", filepath, err)
}
return nil
}
func (d *Onedrive) updateMetadata(ctx context.Context, stream model.FileStreamer, filepath string) error {
url := d.GetMetaUrl(false, filepath)
metadata := toAPIMetadata(stream)
// ApiDoc: https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_update?view=odsp-graph-online
_, err := d.Request(url, http.MethodPatch, func(req *resty.Request) {
req.SetBody(metadata).SetContext(ctx)
}, nil)
return err return err
} }
func toAPIMetadata(stream model.FileStreamer) Metadata {
metadata := Metadata{
FileSystemInfo: &FileSystemInfoFacet{},
}
if !stream.ModTime().IsZero() {
metadata.FileSystemInfo.LastModifiedDateTime = stream.ModTime()
}
if !stream.CreateTime().IsZero() {
metadata.FileSystemInfo.CreatedDateTime = stream.CreateTime()
}
if stream.CreateTime().IsZero() && !stream.ModTime().IsZero() {
metadata.FileSystemInfo.CreatedDateTime = stream.CreateTime()
}
return metadata
}
func (d *Onedrive) upBig(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { func (d *Onedrive) upBig(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
url := d.GetMetaUrl(false, stdpath.Join(dstDir.GetPath(), stream.GetName())) + "/createUploadSession" url := d.GetMetaUrl(false, stdpath.Join(dstDir.GetPath(), stream.GetName())) + "/createUploadSession"
res, err := d.Request(url, http.MethodPost, nil, nil) metadata := map[string]interface{}{"item": toAPIMetadata(stream)}
res, err := d.Request(url, http.MethodPost, func(req *resty.Request) {
req.SetBody(metadata).SetContext(ctx)
}, nil)
if err != nil { if err != nil {
return err return err
} }