Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 52 additions & 5 deletions drivers/onedrive_sharelink/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type OnedriveSharelink struct {

headerMu sync.RWMutex
sg singleflight.Group[http.Header]

listURL string
}

func (d *OnedriveSharelink) Config() driver.Config {
Expand Down Expand Up @@ -87,12 +89,31 @@ func (d *OnedriveSharelink) Drop(ctx context.Context) error {
return nil
}

// relativePath converts the full virtual path from OpenList to a path relative
// to the shared folder's root. When root_folder_path is configured, OpenList
// passes the full path including that prefix.
func (d *OnedriveSharelink) relativePath(virtualPath string) string {
if d.RootFolderPath == "" || d.RootFolderPath == "/" {
return virtualPath
}
root := utils.FixAndCleanPath(d.RootFolderPath)
vpath := utils.FixAndCleanPath(virtualPath)
if vpath == root {
return "/"
}
if strings.HasPrefix(vpath, root+"/") {
return utils.FixAndCleanPath(strings.TrimPrefix(vpath, root))
}
return virtualPath
}

func (d *OnedriveSharelink) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
files, err := d.getFiles(ctx, dir.GetPath())
relPath := d.relativePath(dir.GetPath())
files, err := d.getFiles(ctx, relPath)
if err != nil {
return nil, err
}
folderSizes, err := d.driveChildrenFolderSizes(ctx, dir.GetPath())
folderSizes, err := d.driveChildrenFolderSizes(ctx, relPath)
if err != nil {
log.Warnf("onedrive_sharelink: failed to get folder sizes for %s: %+v", dir.GetPath(), err)
}
Expand Down Expand Up @@ -146,7 +167,7 @@ func (d *OnedriveSharelink) MakeDir(ctx context.Context, parentDir model.Obj, di
if err != nil {
return err
}
apiURL := injectAccessToken(d.drivePathAPIURL(parentDir.GetPath())+"/children", token)
apiURL := injectAccessToken(d.drivePathAPIURL(d.relativePath(parentDir.GetPath()))+"/children", token)
body := map[string]any{
"name": dirName,
"folder": map[string]any{},
Expand Down Expand Up @@ -189,7 +210,7 @@ func (d *OnedriveSharelink) Remove(ctx context.Context, obj model.Obj) error {
}

func (d *OnedriveSharelink) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
info, err := d.createUploadInfo(ctx, stdpath.Join(dstDir.GetPath(), stream.GetName()), stream.GetSize())
info, err := d.createUploadInfo(ctx, stdpath.Join(d.relativePath(dstDir.GetPath()), stream.GetName()), stream.GetSize())
if err != nil {
return err
}
Expand Down Expand Up @@ -295,7 +316,7 @@ func (d *OnedriveSharelink) GetDirectUploadInfo(ctx context.Context, tool string
if tool != "HttpDirect" {
return nil, errs.NotImplement
}
return d.createUploadInfo(ctx, stdpath.Join(dstDir.GetPath(), fileName), fileSize)
return d.createUploadInfo(ctx, stdpath.Join(d.relativePath(dstDir.GetPath()), fileName), fileSize)
}

func (d *OnedriveSharelink) createUploadInfo(ctx context.Context, path string, fileSize int64) (*model.HttpDirectUploadInfo, error) {
Expand Down Expand Up @@ -437,13 +458,38 @@ func (d *OnedriveSharelink) uploadSessionChunk(ctx context.Context, uploadURL st

func (d *OnedriveSharelink) drivePathAPIURL(path string) string {
drivePath := stdpath.Join(d.driveRootPath, path)
// When RootFolderPath is configured, the base drive root needs to take it
// into account so the API targets the correct subfolder.
if d.RootFolderPath != "" && d.RootFolderPath != "/" {
drivePath = stdpath.Join(d.effectiveDriveRootPath(), path)
}
drivePath = utils.FixAndCleanPath(drivePath)
if drivePath == "/" {
return d.DriveURL + "/root"
}
return fmt.Sprintf("%s/root:%s:", d.DriveURL, utils.EncodePath(drivePath, true))
}

// effectiveDriveRootPath computes the drive-relative root path from the
// user-configured RootFolderPath. RootFolderPath is a SharePoint server-relative
// path (e.g. /personal/user/Documents/subfolder); this method extracts the
// portion beyond the document library root (e.g. /subfolder).
func (d *OnedriveSharelink) effectiveDriveRootPath() string {
if d.listURL == "" || d.RootFolderPath == "" || d.RootFolderPath == "/" {
return d.driveRootPath
}
root := strings.TrimRight(d.RootFolderPath, "/")
list := strings.TrimRight(d.listURL, "/")
if root == list {
return "/"
}
prefix := list + "/"
if strings.HasPrefix(root+"/", prefix) {
return utils.FixAndCleanPath(strings.TrimPrefix(root, list))
}
return d.driveRootPath
}

func injectAccessToken(rawURL, token string) string {
if token == "" {
return rawURL
Expand Down Expand Up @@ -561,6 +607,7 @@ func (d *OnedriveSharelink) refreshDriveContextFromRedirect(ctx context.Context,
d.DriveAccessToken = ctxInfo.DriveInfo.DriveAccessToken
d.DriveTokenTime = time.Now().Unix()
d.driveRootPath = rootPath
d.listURL = ctxInfo.ListURL
d.headerMu.Unlock()
return nil
}
Expand Down
5 changes: 5 additions & 0 deletions drivers/onedrive_sharelink/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
if err != nil {
return nil, err
}
// If the user configured a root_folder_path, use it as the initial root
// folder so the GraphQL query targets the correct subdirectory.
if d.RootFolderPath != "" && d.RootFolderPath != "/" {
rootFolder = d.RootFolderPath
}
log.Debugln("rootFolder:", rootFolder)
// Extract the relative path up to and including "Documents"
relativePath := strings.Split(rootFolder, "Documents")[0] + "Documents"
Expand Down