123 lines
3.3 KiB
Go
123 lines
3.3 KiB
Go
package nextcloud
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
// PublicShareBinding maps a public link token to owner storage paths.
|
|
type PublicShareBinding struct {
|
|
Token string
|
|
OwnerID string
|
|
SharePath string // OCS path, e.g. /Documents/hello.docx or /Documents
|
|
ItemType string // file | folder
|
|
}
|
|
|
|
func (b *PublicShareBinding) IsSingleFile() bool {
|
|
return strings.EqualFold(strings.TrimSpace(b.ItemType), "file")
|
|
}
|
|
|
|
// ClientSourcePath resolves the logical client path for a shared item.
|
|
// Single-file shares expose WebDAV at "/" but editors use /filename.
|
|
func (b *PublicShareBinding) ClientSourcePath(clientPath, displayName string) string {
|
|
clientPath = NormalizeClientPath(clientPath)
|
|
if clientPath != "/" {
|
|
return clientPath
|
|
}
|
|
if b != nil && b.IsSingleFile() && b.SharePath != "" {
|
|
return NormalizeClientPath("/" + path.Base(strings.TrimPrefix(b.SharePath, "/")))
|
|
}
|
|
if name := strings.TrimSpace(displayName); name != "" {
|
|
return NormalizeClientPath("/" + name)
|
|
}
|
|
return "/"
|
|
}
|
|
|
|
// OwnerPathForClient maps a client-facing path to the owner's Nextcloud path.
|
|
func (b *PublicShareBinding) OwnerPathForClient(clientPath, displayName string) string {
|
|
if b == nil {
|
|
return NormalizeClientPath(clientPath)
|
|
}
|
|
src := b.ClientSourcePath(clientPath, displayName)
|
|
rel := strings.TrimPrefix(src, "/")
|
|
sharePath := NormalizeClientPath(b.SharePath)
|
|
if b.IsSingleFile() {
|
|
dir := path.Dir(strings.TrimPrefix(sharePath, "/"))
|
|
if dir == "." || dir == "" {
|
|
return NormalizeClientPath("/" + rel)
|
|
}
|
|
return NormalizeClientPath(path.Join("/", dir, rel))
|
|
}
|
|
if sharePath == "/" || sharePath == "" {
|
|
return NormalizeClientPath("/" + rel)
|
|
}
|
|
return NormalizeClientPath(path.Join(sharePath, rel))
|
|
}
|
|
|
|
func normalizeOCSSharePath(p string) string {
|
|
p = strings.TrimSpace(p)
|
|
if p == "" {
|
|
return "/"
|
|
}
|
|
if !strings.HasPrefix(p, "/") {
|
|
p = "/" + p
|
|
}
|
|
return NormalizeClientPath(p)
|
|
}
|
|
|
|
// ResolvePublicShareBinding resolves owner + OCS share metadata for a public token.
|
|
func (c *Client) ResolvePublicShareBinding(ctx context.Context, token, password string) (*PublicShareBinding, error) {
|
|
token = strings.TrimSpace(token)
|
|
if token == "" {
|
|
return nil, ErrInvalidPublicShare
|
|
}
|
|
ownerID, err := c.getPublicShareOwnerID(ctx, token, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ownerID = strings.TrimSpace(ownerID)
|
|
if ownerID == "" {
|
|
return nil, fmt.Errorf("public share owner not found")
|
|
}
|
|
|
|
shares, err := c.ListShares(ctx, ownerID, "")
|
|
if err == nil {
|
|
for _, sh := range shares {
|
|
if strings.TrimSpace(sh.Token) != token {
|
|
continue
|
|
}
|
|
itemType := strings.TrimSpace(sh.ItemType)
|
|
if itemType == "" {
|
|
itemType = "folder"
|
|
}
|
|
return &PublicShareBinding{
|
|
Token: token,
|
|
OwnerID: ownerID,
|
|
SharePath: normalizeOCSSharePath(sh.Path),
|
|
ItemType: itemType,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
view, err := c.GetPublicShare(ctx, token, "/", password)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("public share token not found: %w", err)
|
|
}
|
|
itemType := strings.TrimSpace(view.ItemType)
|
|
if itemType == "" {
|
|
itemType = "folder"
|
|
}
|
|
sharePath := "/"
|
|
if itemType == "file" && strings.TrimSpace(view.Name) != "" {
|
|
sharePath = normalizeOCSSharePath("/" + view.Name)
|
|
}
|
|
return &PublicShareBinding{
|
|
Token: token,
|
|
OwnerID: ownerID,
|
|
SharePath: sharePath,
|
|
ItemType: itemType,
|
|
}, nil
|
|
}
|