chore: keep host/client specifics out of the tree (env & config)
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 59s
Tests / Test (Go stable) (pull_request) Successful in 1m7s
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 59s
Tests / Test (Go stable) (pull_request) Successful in 1m7s
Showroom-safe: the tree no longer carries internal hosts, IPs, ports, personal names, client domains or client file names. Behaviour is unchanged and now supplied per deployment. - catalog: hardcoded mail-org / project classifiers become a YAML-driven Classifier (OO_CATALOG_CONFIG or --config); neutral default classifies nothing as work. New catalog/classify.go + example + tests. - storage_fallback: drop the baked-in MinIO endpoint IP; require MINIO_ENDPOINT (+ keys) from the env. - kontolink: build DocEditor links from $ONLYOFFICE_URL instead of a hardcoded portal host; kontoblatt: no client file id in the output name. - oo: load .env CLI-wide (bootstrap.LoadEnv in execute) so non-authenticating commands (catalog scans) also see config. - genericize comments/docs/fixtures (AGENTS, README, .env.example, crm-associations, catalog tests, ES/pdfattach tests, mails).
This commit is contained in:
@@ -162,7 +162,7 @@ func main() {
|
||||
}
|
||||
fmt.Printf("source: id=%s title=%q folder=%s\n", fileID, title, folder)
|
||||
|
||||
name := "Kontoblatt-1591-2025-Zusammenfassung.xlsx"
|
||||
name := "Kontoblatt-Zusammenfassung.xlsx"
|
||||
tmp := "/tmp/opencode/" + name
|
||||
data, _ := os.ReadFile(outPath)
|
||||
if err := os.WriteFile(tmp, data, 0o600); err != nil {
|
||||
|
||||
+16
-2
@@ -76,7 +76,15 @@ func nearest(cands []entry, rd time.Time) (entry, bool) {
|
||||
return cands[best], true
|
||||
}
|
||||
|
||||
const linkPrefix = "https://office.pro-dukt.de/Products/Files/DocEditor.aspx?fileid="
|
||||
// portalBaseFromEnv resolves the portal base URL used to build document links.
|
||||
func portalBaseFromEnv() string {
|
||||
for _, k := range []string{"ONLYOFFICE_URL", "ONLYOFFICE_HOST", "OO_URL"} {
|
||||
if v := strings.TrimSpace(os.Getenv(k)); v != "" {
|
||||
return strings.TrimRight(v, "/")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
id, path, title, norm string
|
||||
@@ -91,6 +99,12 @@ func main() {
|
||||
}
|
||||
in, idxPath, out := os.Args[1], os.Args[2], os.Args[3]
|
||||
|
||||
portal := portalBaseFromEnv()
|
||||
if portal == "" {
|
||||
fmt.Fprintln(os.Stderr, "set ONLYOFFICE_URL (or ONLYOFFICE_HOST/OO_URL) to build document links")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
idxRaw, err := os.ReadFile(idxPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -153,7 +167,7 @@ func main() {
|
||||
continue
|
||||
}
|
||||
ref, _ := excelize.CoordinatesToCellName(8, i+1)
|
||||
if err := f.SetCellValue(sheet, ref, linkPrefix+e.id); err != nil {
|
||||
if err := f.SetCellValue(sheet, ref, portal+"/Products/Files/DocEditor.aspx?fileid="+e.id); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
used[e.id] = true
|
||||
|
||||
+25
-3
@@ -64,6 +64,7 @@ func catalogScanContactsCmd() *cobra.Command {
|
||||
func catalogScanProjectsCmd() *cobra.Command {
|
||||
var outPath string
|
||||
var maxDepth int
|
||||
var configPath string
|
||||
cmd := &cobra.Command{
|
||||
Use: "scan-projects",
|
||||
Short: "Git roots / remotes / top-level dirs → company rows",
|
||||
@@ -72,7 +73,11 @@ func catalogScanProjectsCmd() *cobra.Command {
|
||||
if root == "" {
|
||||
return fmt.Errorf("--root is required")
|
||||
}
|
||||
doc, err := catalog.ScanProjectsRoot(root, maxDepth)
|
||||
cl, err := catalogClassifier(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
doc, err := catalog.ScanProjectsRootOpts(root, maxDepth, catalog.ScanOptions{Classifier: cl})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -81,6 +86,7 @@ func catalogScanProjectsCmd() *cobra.Command {
|
||||
}
|
||||
cmd.Flags().String("root", "", "projects directory (local path)")
|
||||
cmd.Flags().IntVar(&maxDepth, "max-depth", 4, "max directory depth for git roots")
|
||||
cmd.Flags().StringVar(&configPath, "config", "", "classification rules YAML (default $OO_CATALOG_CONFIG)")
|
||||
cmd.Flags().StringVarP(&outPath, "out", "O", "", "write YAML to this path")
|
||||
_ = cmd.MarkFlagRequired("root")
|
||||
return cmd
|
||||
@@ -89,6 +95,7 @@ func catalogScanProjectsCmd() *cobra.Command {
|
||||
func catalogScanThunderbirdCmd() *cobra.Command {
|
||||
var outPath string
|
||||
var mboxHeaders bool
|
||||
var configPath string
|
||||
cmd := &cobra.Command{
|
||||
Use: "scan-thunderbird",
|
||||
Short: "Thunderbird profiles: abook/history.mab + Gloda SQLite contacts",
|
||||
@@ -98,13 +105,18 @@ func catalogScanThunderbirdCmd() *cobra.Command {
|
||||
- optional --mbox-headers: From/To/Cc/Reply-To from mbox folder files (no bodies)
|
||||
|
||||
Noisy senders (noreply, Amazon marketplace, GitHub reply, …) are skipped.
|
||||
Default zone is private; known work domains (e.g. wheregroup.com) get zone=warm role=work.`,
|
||||
Default zone is private; work domains/names are classified from the rules in
|
||||
$OO_CATALOG_CONFIG (or --config) — none are hardcoded.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
root, _ := cmd.Flags().GetString("root")
|
||||
if root == "" {
|
||||
return fmt.Errorf("--root is required")
|
||||
}
|
||||
doc, err := catalog.ScanThunderbirdRootOpts(root, catalog.ScanOptions{MboxHeaders: mboxHeaders})
|
||||
cl, err := catalogClassifier(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
doc, err := catalog.ScanThunderbirdRootOpts(root, catalog.ScanOptions{MboxHeaders: mboxHeaders, Classifier: cl})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -113,11 +125,21 @@ Default zone is private; known work domains (e.g. wheregroup.com) get zone=warm
|
||||
}
|
||||
cmd.Flags().String("root", "", "Thunderbird profile or parent directory (local path)")
|
||||
cmd.Flags().BoolVar(&mboxHeaders, "mbox-headers", false, "also extract emails from mbox From/To/Cc headers")
|
||||
cmd.Flags().StringVar(&configPath, "config", "", "classification rules YAML (default $OO_CATALOG_CONFIG)")
|
||||
cmd.Flags().StringVarP(&outPath, "out", "O", "", "write YAML to this path")
|
||||
_ = cmd.MarkFlagRequired("root")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// catalogClassifier loads classification rules from --config, else
|
||||
// $OO_CATALOG_CONFIG, else the neutral default (no rules).
|
||||
func catalogClassifier(configPath string) (*catalog.Classifier, error) {
|
||||
if configPath == "" {
|
||||
return catalog.LoadClassifierFromEnv()
|
||||
}
|
||||
return catalog.LoadClassifier(configPath)
|
||||
}
|
||||
|
||||
func catalogMergeCmd() *cobra.Command {
|
||||
var inputs []string
|
||||
var outPath string
|
||||
|
||||
+3
-1
@@ -31,7 +31,9 @@ func init() {
|
||||
}
|
||||
|
||||
// execute runs the root command. Exported only to main.go in the same package.
|
||||
func execute() error { return rootCmd.Execute() }
|
||||
// .env is loaded CLI-wide so non-authenticating commands (e.g. catalog scans)
|
||||
// also see configuration such as OO_CATALOG_CONFIG.
|
||||
func execute() error { bootstrap.LoadEnv(); return rootCmd.Execute() }
|
||||
|
||||
// newOO loads env (only .env in CWD) and returns an authenticated client.
|
||||
// godotenv is a CLI-only concern; the library itself never loads dotfiles.
|
||||
|
||||
Reference in New Issue
Block a user