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
115 lines
3.8 KiB
Go
115 lines
3.8 KiB
Go
// Package onlyoffice provides a Go client for the OnlyOffice Workspace
|
|
// (formerly ONLYOFFICE) REST API. It is organised as a flat single package
|
|
// intentionally: a single *Client exposes Projects, Tasks, Calendar, CRM and
|
|
// Files operations as receiver methods. Domain split is by file, not by
|
|
// subpackage, to keep call sites uniform (c.ListContacts, c.GetTasks,
|
|
// c.AddEvent, c.UploadOpportunityFile all live on the same handle).
|
|
//
|
|
// The CLI binary `oo` (see cmd/oo) is a thin cobra wrapper on top of this
|
|
// library and mirrors the Python cv/bin/office reference tooling.
|
|
package onlyoffice
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/cookiejar"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// Client of OnlyOffice API uses credentials to get a token and query the API
|
|
// by every request.
|
|
//
|
|
// Construct with NewClient; optionally set fallbacks via SetDefaults. The
|
|
// zero value is NOT usable — credentials are required. A single client is
|
|
// safe for sequential use from one goroutine; for concurrent use, callers
|
|
// should wrap with their own synchronization or create one client per
|
|
// goroutine.
|
|
type Client struct {
|
|
client *http.Client
|
|
credentials *Credentials
|
|
token *Token
|
|
|
|
defaults Defaults // optional fallbacks for calendar/project IDs
|
|
selfID string // cached /api/2.0/people/@self id
|
|
noteCatID int // cached CRM history category id for "note"
|
|
|
|
folderTitles map[string]string // cached Documents folder id -> title (F9)
|
|
folderTitlesMu sync.Mutex
|
|
}
|
|
|
|
// NewClient returns a new Client backed by http.DefaultClient.
|
|
func NewClient(c Credentials) *Client {
|
|
jar, _ := cookiejar.New(nil)
|
|
return &Client{
|
|
client: &http.Client{Jar: jar},
|
|
credentials: &c,
|
|
}
|
|
}
|
|
|
|
// Credentials of OnlyOffice User. The Url field is NOT sent with the auth
|
|
// payload — it only determines the host.
|
|
type Credentials struct {
|
|
Url string `json:"-"`
|
|
User string `json:"userName"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
// Defaults holds optional fallbacks used by package-level helpers when callers
|
|
// pass an empty identifier (calendar or project). Set via (*Client).SetDefaults
|
|
// or read from env via GetEnvironmentDefaults.
|
|
type Defaults struct {
|
|
CalendarID string
|
|
ProjectID string
|
|
}
|
|
|
|
// SetDefaults configures optional identifiers used as fallbacks by methods
|
|
// such as AddEvent (when calendarID == "") or AddTask (when projectID == "").
|
|
func (c *Client) SetDefaults(d Defaults) { c.defaults = d }
|
|
|
|
// GetEnvironmentCredentials reads OnlyOffice credentials from environment.
|
|
//
|
|
// Primary variables (documented):
|
|
// - ONLYOFFICE_URL
|
|
// - ONLYOFFICE_USER
|
|
// - ONLYOFFICE_PASS
|
|
//
|
|
// Additional aliases accepted for interoperability with sibling tools:
|
|
// - ONLYOFFICE_HOST (alias for ONLYOFFICE_URL)
|
|
// - ONLYOFFICE_NAME (alias for ONLYOFFICE_USER)
|
|
// - ONLYOFFICE_PASSWORD (alias for ONLYOFFICE_PASS)
|
|
func GetEnvironmentCredentials() Credentials {
|
|
url := firstNonEmpty(os.Getenv("ONLYOFFICE_URL"), os.Getenv("ONLYOFFICE_HOST"))
|
|
url = strings.TrimRight(url, "/")
|
|
return Credentials{
|
|
Url: url,
|
|
User: firstNonEmpty(os.Getenv("ONLYOFFICE_USER"), os.Getenv("ONLYOFFICE_NAME")),
|
|
Password: firstNonEmpty(os.Getenv("ONLYOFFICE_PASS"), os.Getenv("ONLYOFFICE_PASSWORD")),
|
|
}
|
|
}
|
|
|
|
// GetEnvironmentDefaults reads optional library defaults from environment:
|
|
//
|
|
// - ONLYOFFICE_CALENDAR_ID (default: "1")
|
|
// - ONLYOFFICE_PROJECT_ID (alias: ONLYOFFICE_CALENDAR_PROJECT_ID; default: "33")
|
|
func GetEnvironmentDefaults() Defaults {
|
|
return Defaults{
|
|
CalendarID: firstNonEmpty(os.Getenv("ONLYOFFICE_CALENDAR_ID"), "1"),
|
|
ProjectID: firstNonEmpty(
|
|
os.Getenv("ONLYOFFICE_PROJECT_ID"),
|
|
os.Getenv("ONLYOFFICE_CALENDAR_PROJECT_ID"),
|
|
"33",
|
|
),
|
|
}
|
|
}
|
|
|
|
// firstNonEmpty returns the first non-empty trimmed value, or "" if none.
|
|
func firstNonEmpty(vals ...string) string {
|
|
for _, v := range vals {
|
|
if s := strings.TrimSpace(v); s != "" {
|
|
return s
|
|
}
|
|
}
|
|
return ""
|
|
}
|