Add filesystem inventory (VCF, contact folders, project trees) into a reviewable YAML catalog, match against live OnlyOffice, and upsert only rows with approve:true. Includes FindPersonByEmail for email-keyed persons.
188 lines
4.2 KiB
Go
188 lines
4.2 KiB
Go
package catalog
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
onlyoffice "github.com/eslider/go-onlyoffice"
|
|
)
|
|
|
|
// ApplyResult summarizes one apply pass.
|
|
type ApplyResult struct {
|
|
Created int `json:"created"`
|
|
Updated int `json:"updated"`
|
|
Skipped int `json:"skipped"`
|
|
Errors []string `json:"errors,omitempty"`
|
|
DryRun bool `json:"dry_run"`
|
|
}
|
|
|
|
// ApplyApproved creates/updates OO contacts for entries with approve=true.
|
|
func ApplyApproved(ctx context.Context, client *onlyoffice.Client, doc *Document, dryRun bool) (*ApplyResult, error) {
|
|
res := &ApplyResult{DryRun: dryRun}
|
|
for i := range doc.Entries {
|
|
e := &doc.Entries[i]
|
|
if !e.Approve {
|
|
res.Skipped++
|
|
continue
|
|
}
|
|
if e.Status == "conflict" {
|
|
res.Skipped++
|
|
res.Errors = append(res.Errors, e.ID+": conflict — resolve manually")
|
|
continue
|
|
}
|
|
if dryRun {
|
|
if e.OOID != "" || e.Status == "exists" {
|
|
res.Updated++
|
|
} else {
|
|
res.Created++
|
|
}
|
|
continue
|
|
}
|
|
created, err := applyOne(ctx, client, e)
|
|
if err != nil {
|
|
res.Errors = append(res.Errors, e.ID+": "+err.Error())
|
|
continue
|
|
}
|
|
if created {
|
|
res.Created++
|
|
} else {
|
|
res.Updated++
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func applyOne(ctx context.Context, client *onlyoffice.Client, e *Entry) (created bool, err error) {
|
|
switch e.Kind {
|
|
case "company":
|
|
return applyCompany(ctx, client, e)
|
|
case "person":
|
|
return applyPerson(ctx, client, e)
|
|
default:
|
|
return false, fmt.Errorf("unknown kind %q", e.Kind)
|
|
}
|
|
}
|
|
|
|
func applyCompany(ctx context.Context, client *onlyoffice.Client, e *Entry) (bool, error) {
|
|
name := strings.TrimSpace(e.Name)
|
|
if name == "" {
|
|
return false, fmt.Errorf("company missing name")
|
|
}
|
|
var co map[string]any
|
|
var err error
|
|
if e.OOID != "" {
|
|
co, err = client.GetContact(ctx, e.OOID)
|
|
} else {
|
|
co, err = client.FindCompany(ctx, name)
|
|
}
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
created := false
|
|
if co == nil {
|
|
co, err = client.CreateCompany(ctx, name)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
created = true
|
|
}
|
|
id := contactIDString(co)
|
|
e.OOID = id
|
|
if err := ensureContactInfos(ctx, client, id, e); err != nil {
|
|
return created, err
|
|
}
|
|
e.Status = "applied"
|
|
if created {
|
|
e.Notes = "created"
|
|
} else {
|
|
e.Notes = "updated"
|
|
}
|
|
return created, nil
|
|
}
|
|
|
|
func applyPerson(ctx context.Context, client *onlyoffice.Client, e *Entry) (bool, error) {
|
|
first := strings.TrimSpace(e.First)
|
|
last := strings.TrimSpace(e.Last)
|
|
if first == "" && last == "" {
|
|
first, last = SplitDisplayName(e.Name)
|
|
}
|
|
if first == "" {
|
|
first = strings.TrimSpace(e.Name)
|
|
}
|
|
if first == "" {
|
|
return false, fmt.Errorf("person missing name")
|
|
}
|
|
if last == "" {
|
|
last = "-"
|
|
}
|
|
|
|
var p map[string]any
|
|
var err error
|
|
if e.OOID != "" {
|
|
p, err = client.GetContact(ctx, e.OOID)
|
|
} else if len(e.Emails) > 0 {
|
|
p, err = client.FindPersonByEmail(ctx, e.Emails[0])
|
|
} else {
|
|
p, err = client.FindPerson(ctx, first, last)
|
|
}
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
created := false
|
|
companyID := 0
|
|
if e.Org != "" {
|
|
if co, ferr := client.FindCompany(ctx, e.Org); ferr == nil && co != nil {
|
|
companyID, _ = strconv.Atoi(contactIDString(co))
|
|
}
|
|
}
|
|
if p == nil {
|
|
about := ""
|
|
if e.Org != "" {
|
|
about = "org: " + e.Org
|
|
}
|
|
p, err = client.CreatePerson(ctx, first, last, companyID, "", about)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
created = true
|
|
}
|
|
id := contactIDString(p)
|
|
e.OOID = id
|
|
if err := ensureContactInfos(ctx, client, id, e); err != nil {
|
|
return created, err
|
|
}
|
|
e.Status = "applied"
|
|
if created {
|
|
e.Notes = "created"
|
|
} else {
|
|
e.Notes = "updated"
|
|
}
|
|
return created, nil
|
|
}
|
|
|
|
func ensureContactInfos(ctx context.Context, client *onlyoffice.Client, contactID string, e *Entry) error {
|
|
existing, err := client.GetContact(ctx, contactID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i, em := range e.Emails {
|
|
if onlyoffice.HasContactInfo(existing, "Email", em) {
|
|
continue
|
|
}
|
|
if _, err := client.AddContactInfo(ctx, contactID, "Email", em, "Work", i == 0); err != nil {
|
|
return fmt.Errorf("add email %s: %w", em, err)
|
|
}
|
|
}
|
|
for _, ph := range e.Phones {
|
|
if onlyoffice.HasContactInfo(existing, "Phone", ph) {
|
|
continue
|
|
}
|
|
if _, err := client.AddContactInfo(ctx, contactID, "Phone", ph, "Work", false); err != nil {
|
|
return fmt.Errorf("add phone %s: %w", ph, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|