8e61cd7ec4
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>
129 lines
4.6 KiB
Go
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")
|
|
}
|