Release Please / Release Please (push) Skipped
Release / GoReleaser (push) Skipped
Tests / Secret scan (gitleaks) (push) Skipped
Tests / Test (Go 1.25) (push) Skipped
Tests / Test (Go stable) (push) Skipped
Tests / Secret scan (gitleaks) (pull_request) Successful in 4s
Tests / Test (Go 1.25) (pull_request) Successful in 21s
Tests / Test (Go stable) (pull_request) Successful in 26s
80 lines
2.4 KiB
Go
80 lines
2.4 KiB
Go
package onlyoffice
|
|
|
|
// Human-readable folder paths for search results (F9). The OnlyOffice ES
|
|
// index stores only ancestor folder ids; titles live in the Documents tree, so
|
|
// resolving a path costs one GET /api/2.0/files/{id} per distinct folder,
|
|
// cached on the client. Folders that cannot be listed (e.g. a section root)
|
|
// fall back to their id, so a path is always produced.
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
)
|
|
|
|
// FolderTitle returns the title of a Documents folder id, cached on the client.
|
|
// An empty id yields an empty title. Unknown/unlistable ids (section roots)
|
|
// return ("", nil) so callers can fall back to the id.
|
|
func (c *Client) FolderTitle(ctx context.Context, folderID string) (string, error) {
|
|
folderID = strings.TrimSpace(folderID)
|
|
if folderID == "" {
|
|
return "", nil
|
|
}
|
|
c.folderTitlesMu.Lock()
|
|
if c.folderTitles != nil {
|
|
if t, ok := c.folderTitles[folderID]; ok {
|
|
c.folderTitlesMu.Unlock()
|
|
return t, nil
|
|
}
|
|
}
|
|
c.folderTitlesMu.Unlock()
|
|
|
|
title := ""
|
|
out, err := c.ListFolder(ctx, folderID)
|
|
if err == nil {
|
|
if cur, ok := out["current"].(map[string]any); ok {
|
|
if s, ok := cur["title"].(string); ok {
|
|
title = strings.TrimSpace(s)
|
|
}
|
|
}
|
|
}
|
|
|
|
c.folderTitlesMu.Lock()
|
|
if c.folderTitles == nil {
|
|
c.folderTitles = map[string]string{}
|
|
}
|
|
c.folderTitles[folderID] = title
|
|
c.folderTitlesMu.Unlock()
|
|
return title, nil
|
|
}
|
|
|
|
// FolderPath resolves an ancestor folder id chain (root → leaf, as the ES
|
|
// backend reports it) into folder titles, falling back to the id when a title
|
|
// cannot be read. The result never fails on a single lookup: only the whole
|
|
// call honours ctx cancellation.
|
|
func (c *Client) FolderPath(ctx context.Context, ids []string) []string {
|
|
out := make([]string, 0, len(ids))
|
|
for _, id := range ids {
|
|
if err := ctx.Err(); err != nil {
|
|
break
|
|
}
|
|
title, err := c.FolderTitle(ctx, id)
|
|
if err != nil || title == "" {
|
|
title = id
|
|
}
|
|
out = append(out, title)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// UniquePath builds a stable, human-readable, unique path for a result: the
|
|
// resolved folder chain plus the file title. "." separates nothing — the
|
|
// segments are joined with "/", matching the Documents breadcrumb the web UI
|
|
// shows.
|
|
func (c *Client) UniquePath(ctx context.Context, folderPath []string, title string) string {
|
|
parts := c.FolderPath(ctx, folderPath)
|
|
if t := strings.TrimSpace(title); t != "" {
|
|
parts = append(parts, t)
|
|
}
|
|
return strings.Join(parts, "/")
|
|
}
|