Files
deploy-felhom-compose/controller/internal/integrations/onlyoffice_filebrowser.go
T
admin 8e61cd7ec4 feat: comprehensive INFO/WARN/ERROR logging across all controller modules
Add structured operational logging at INFO, WARN, and ERROR levels to
every controller module. Standardize custom prefixes ([GEO], [SCHED],
[SYNC]) to use [INFO/WARN/ERROR] [module] format. Fix misleveled logs
(WARN->ERROR for data loss scenarios, WARN->INFO for routine operations).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:58:27 +01:00

129 lines
4.6 KiB
Go

package integrations
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// OnlyOfficeFileBrowserHandler enables/disables OnlyOffice document editing in FileBrowser Quantum.
type OnlyOfficeFileBrowserHandler struct{}
func (h *OnlyOfficeFileBrowserHandler) Apply(ac *ApplyContext) error {
jwtSecret := ac.ProviderEnv["JWT_SECRET"]
if jwtSecret == "" {
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: JWT_SECRET not set")
return fmt.Errorf("OnlyOffice JWT_SECRET nincs beállítva — telepítsd újra az alkalmazást")
}
subdomain := ac.ProviderEnv["SUBDOMAIN"]
if subdomain == "" && ac.ProviderMeta != nil {
subdomain = ac.ProviderMeta.Subdomain
}
if subdomain == "" {
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: subdomain unknown")
return fmt.Errorf("OnlyOffice aldomain nem ismert")
}
configPath := filepath.Join(ac.StacksDir, "filebrowser", "config.yaml")
officeURL := fmt.Sprintf("https://%s.%s", subdomain, ac.Domain)
ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Apply: jwtSecretPresent=%v subdomain=%s configPath=%s officeURL=%s", jwtSecret != "", subdomain, configPath, officeURL)
configData, err := os.ReadFile(configPath)
if err != nil {
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: %v", err)
return fmt.Errorf("FileBrowser config olvasási hiba: %w", err)
}
// Remove any existing integrations section, then append the new one
configStr := removeIntegrationsSection(string(configData))
internalURL := "http://onlyoffice:80"
integrationsBlock := fmt.Sprintf("integrations:\n office:\n url: %q\n internalUrl: %q\n secret: %q\n viewOnly: false\n",
officeURL, internalURL, jwtSecret)
configStr = strings.TrimRight(configStr, "\n") + "\n" + integrationsBlock
// Atomic write
tmpPath := configPath + ".tmp"
if err := os.WriteFile(tmpPath, []byte(configStr), 0644); err != nil {
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: %v", err)
return fmt.Errorf("config írási hiba: %w", err)
}
if err := os.Rename(tmpPath, configPath); err != nil {
_ = os.Remove(tmpPath)
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: %v", err)
return fmt.Errorf("config átnevezési hiba: %w", err)
}
ac.Logger.Printf("[INFO] FileBrowser config updated with OnlyOffice integration")
return ac.RestartStack("filebrowser")
}
func (h *OnlyOfficeFileBrowserHandler) Revoke(ac *ApplyContext) error {
configPath := filepath.Join(ac.StacksDir, "filebrowser", "config.yaml")
ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Revoke: configPath=%s", configPath)
configData, err := os.ReadFile(configPath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser revoke: %v", err)
return fmt.Errorf("config olvasási hiba: %w", err)
}
cleaned := removeIntegrationsSection(string(configData))
hadIntegrations := cleaned != string(configData)
ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Revoke: integrationsSectionFound=%v", hadIntegrations)
if !hadIntegrations {
return nil // no integrations section, nothing to remove
}
tmpPath := configPath + ".tmp"
if err := os.WriteFile(tmpPath, []byte(cleaned), 0644); err != nil {
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser revoke: %v", err)
return fmt.Errorf("config írási hiba: %w", err)
}
if err := os.Rename(tmpPath, configPath); err != nil {
_ = os.Remove(tmpPath)
ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser revoke: %v", err)
return fmt.Errorf("config átnevezési hiba: %w", err)
}
ac.Logger.Printf("[INFO] FileBrowser config cleaned — OnlyOffice integration removed")
return ac.RestartStack("filebrowser")
}
// removeIntegrationsSection strips the integrations: YAML block from a config string.
// It removes from the line starting with "integrations:" to the next unindented key or EOF.
func removeIntegrationsSection(config string) string {
lines := strings.Split(config, "\n")
var result []string
inBlock := false
for _, line := range lines {
if strings.HasPrefix(line, "integrations:") {
inBlock = true
continue
}
if inBlock {
trimmed := strings.TrimRight(line, " \t\r")
if trimmed == "" {
continue // skip blank lines within block
}
if line[0] != ' ' && line[0] != '\t' {
// New top-level key — end of integrations block
inBlock = false
result = append(result, line)
}
// else: still inside indented block, skip
continue
}
result = append(result, line)
}
return strings.Join(result, "\n")
}