Files
phishingclub/backend/model/autoPruneOption.go
Ronni Skansing 83f9e8f279 add auto remove orphans
fix orphans in dynamic groups not included

Signed-off-by: Ronni Skansing <rskansing@gmail.com>
2026-03-29 16:30:01 +02:00

101 lines
3.0 KiB
Go

package model
import (
"encoding/json"
"slices"
"github.com/go-errors/errors"
"github.com/google/uuid"
"github.com/phishingclub/phishingclub/data"
"github.com/phishingclub/phishingclub/errs"
"github.com/phishingclub/phishingclub/validate"
"github.com/phishingclub/phishingclub/vo"
)
// AutoPruneOption holds the auto prune orphaned recipients setting for both
// the global scope and all per company overrides. It is stored as a
// JSON value under the key data.OptionKeyAutoPruneOrphanedRecipients.
//
// example stored value:
//
// {"enabled":false,"companies":["uuid1","uuid2"]}
type AutoPruneOption struct {
// Enabled is the global (shared / no-company) auto prune flag.
Enabled bool `json:"enabled"`
// Companies is the list of company UUIDs that have opted in to auto pruning.
// a company not present in this list will not be pruned.
Companies []string `json:"companies,omitempty"`
}
// NewAutoPruneOptionDefault returns a disabled AutoPruneOption with no company entries.
func NewAutoPruneOptionDefault() *AutoPruneOption {
return &AutoPruneOption{
Enabled: false,
Companies: []string{},
}
}
// NewAutoPruneOptionFromJSON deserialises an AutoPruneOption from JSON bytes.
func NewAutoPruneOptionFromJSON(jsonData []byte) (*AutoPruneOption, error) {
opt := &AutoPruneOption{}
if err := json.Unmarshal(jsonData, opt); err != nil {
return nil, validate.WrapErrorWithField(
errs.NewValidationError(errors.New("invalid format")),
"AutoPruneOption",
)
}
if opt.Companies == nil {
opt.Companies = []string{}
}
return opt, nil
}
// NewAutoPruneOptionFromOption deserialises an AutoPruneOption from a generic Option model.
func NewAutoPruneOptionFromOption(option *Option) (*AutoPruneOption, error) {
if option == nil {
return nil, errors.New("option cannot be nil")
}
return NewAutoPruneOptionFromJSON([]byte(option.Value.String()))
}
// IsCompanyEnabled returns true if the given company has explicitly opted in to auto pruning.
func (a *AutoPruneOption) IsCompanyEnabled(companyID *uuid.UUID) bool {
return slices.Contains(a.Companies, companyID.String())
}
// SetCompanyEnabled adds or removes the given company from the opted in list.
func (a *AutoPruneOption) SetCompanyEnabled(companyID *uuid.UUID, enabled bool) {
id := companyID.String()
if enabled {
if !slices.Contains(a.Companies, id) {
a.Companies = append(a.Companies, id)
}
return
}
a.Companies = slices.DeleteFunc(a.Companies, func(s string) bool {
return s == id
})
}
// ToJSON serialises the AutoPruneOption to JSON bytes.
func (a *AutoPruneOption) ToJSON() ([]byte, error) {
return json.Marshal(a)
}
// ToOption converts the AutoPruneOption into a generic Option ready to be persisted
// under data.OptionKeyAutoPruneOrphanedRecipients.
func (a *AutoPruneOption) ToOption() (*Option, error) {
j, err := a.ToJSON()
if err != nil {
return nil, errs.Wrap(err)
}
str, err := vo.NewOptionalString1MB(string(j))
if err != nil {
return nil, errs.Wrap(err)
}
return &Option{
Key: *vo.NewString127Must(data.OptionKeyAutoPruneOrphanedRecipients),
Value: *str,
}, nil
}