software steht so weit.
jetzt build + docker build und testen
This commit is contained in:
1 parent
42f0c0accb
commit
ca6cdcca63
90 files changed
+10298
-480
No files matched your search
+49
-19
@@ -50,8 +50,12 @@ type Tenant struct {
|
||||
AllowedDomains []string
|
||||
ValidUntil time.Time
|
||||
Status TenantStatus
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Features []string // freigeschaltete Lizenz-Features (z. B. custom_middleware)
|
||||
// PaymentOverdueSince: seit wann eine Zahlung offen ist (Nullwert = nichts
|
||||
// offen); daraus berechnet die Policy die Mahnstufe.
|
||||
PaymentOverdueSince time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// normalize setzt Defaults (Tier community, Status active, leere
|
||||
@@ -66,6 +70,9 @@ func (t *Tenant) normalize() error {
|
||||
if t.AllowedDomains == nil {
|
||||
t.AllowedDomains = []string{}
|
||||
}
|
||||
if t.Features == nil {
|
||||
t.Features = []string{}
|
||||
}
|
||||
t.ValidUntil = normTime(t.ValidUntil)
|
||||
|
||||
switch {
|
||||
@@ -89,6 +96,11 @@ func (t *Tenant) normalize() error {
|
||||
return invalid("leerer Eintrag in allowed_domains")
|
||||
}
|
||||
}
|
||||
for _, f := range t.Features {
|
||||
if blank(f) {
|
||||
return invalid("leerer Eintrag in features")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -98,40 +110,47 @@ func (s *Store) CreateTenant(ctx context.Context, t Tenant) (Tenant, error) {
|
||||
if err := t.normalize(); err != nil {
|
||||
return Tenant{}, err
|
||||
}
|
||||
domains, err := json.Marshal(t.AllowedDomains)
|
||||
if err != nil {
|
||||
return Tenant{}, err
|
||||
}
|
||||
domains, _ := json.Marshal(t.AllowedDomains)
|
||||
features, _ := json.Marshal(t.Features)
|
||||
now := normTime(s.now())
|
||||
t.CreatedAt, t.UpdatedAt = now, now
|
||||
t.PaymentOverdueSince = time.Time{}
|
||||
|
||||
_, err = s.db.ExecContext(ctx, `INSERT INTO tenants
|
||||
(id, name, email, tier, max_routes, allowed_domains, valid_until, status, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
_, err := s.db.ExecContext(ctx, `INSERT INTO tenants
|
||||
(id, name, email, tier, max_routes, allowed_domains, valid_until, status, created_at, updated_at, features)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
t.ID, t.Name, t.Email, t.Tier, t.MaxRoutes, string(domains),
|
||||
formatTime(t.ValidUntil), t.Status, formatTime(now), formatTime(now))
|
||||
formatTime(t.ValidUntil), t.Status, formatTime(now), formatTime(now), string(features))
|
||||
if err != nil {
|
||||
return Tenant{}, mapConstraint(err, "Mandant "+t.ID)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
const tenantColumns = `id, name, email, tier, max_routes, allowed_domains, valid_until, status, created_at, updated_at`
|
||||
const tenantColumns = `id, name, email, tier, max_routes, allowed_domains, valid_until, status, created_at, updated_at,
|
||||
features, payment_overdue_since`
|
||||
|
||||
func scanTenant(row interface{ Scan(...any) error }) (Tenant, error) {
|
||||
var t Tenant
|
||||
var domains string
|
||||
var domains, features string
|
||||
err := row.Scan(&t.ID, &t.Name, &t.Email, &t.Tier, &t.MaxRoutes, &domains,
|
||||
dbTime{&t.ValidUntil}, &t.Status, dbTime{&t.CreatedAt}, dbTime{&t.UpdatedAt})
|
||||
dbTime{&t.ValidUntil}, &t.Status, dbTime{&t.CreatedAt}, dbTime{&t.UpdatedAt},
|
||||
&features, dbTime{&t.PaymentOverdueSince})
|
||||
if err != nil {
|
||||
return Tenant{}, err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(domains), &t.AllowedDomains); err != nil {
|
||||
return Tenant{}, fmt.Errorf("store: allowed_domains von %s: %w", t.ID, err)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(features), &t.Features); err != nil {
|
||||
return Tenant{}, fmt.Errorf("store: features von %s: %w", t.ID, err)
|
||||
}
|
||||
if t.AllowedDomains == nil {
|
||||
t.AllowedDomains = []string{}
|
||||
}
|
||||
if t.Features == nil {
|
||||
t.Features = []string{}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
@@ -168,15 +187,14 @@ func (s *Store) UpdateTenant(ctx context.Context, t Tenant) (Tenant, error) {
|
||||
if err := t.normalize(); err != nil {
|
||||
return Tenant{}, err
|
||||
}
|
||||
domains, err := json.Marshal(t.AllowedDomains)
|
||||
if err != nil {
|
||||
return Tenant{}, err
|
||||
}
|
||||
domains, _ := json.Marshal(t.AllowedDomains)
|
||||
features, _ := json.Marshal(t.Features)
|
||||
res, err := s.db.ExecContext(ctx, `UPDATE tenants SET
|
||||
name = ?, email = ?, tier = ?, max_routes = ?, allowed_domains = ?, valid_until = ?, status = ?, updated_at = ?
|
||||
name = ?, email = ?, tier = ?, max_routes = ?, allowed_domains = ?, valid_until = ?, status = ?, updated_at = ?,
|
||||
features = ?
|
||||
WHERE id = ?`,
|
||||
t.Name, t.Email, t.Tier, t.MaxRoutes, string(domains), formatTime(t.ValidUntil), t.Status,
|
||||
formatTime(s.now()), t.ID)
|
||||
formatTime(s.now()), string(features), t.ID)
|
||||
if err := requireAffected(res, err, "Mandant "+t.ID); err != nil {
|
||||
return Tenant{}, err
|
||||
}
|
||||
@@ -193,6 +211,18 @@ func (s *Store) SetTenantStatus(ctx context.Context, id string, status TenantSta
|
||||
return requireAffected(res, err, "Mandant "+id)
|
||||
}
|
||||
|
||||
// SetTenantPayment setzt, seit wann eine Zahlung offen ist (Nullwert =
|
||||
// bezahlt). Grundlage der Mahnstufen.
|
||||
func (s *Store) SetTenantPayment(ctx context.Context, id string, overdueSince time.Time) error {
|
||||
var v any
|
||||
if !overdueSince.IsZero() {
|
||||
v = formatTime(overdueSince)
|
||||
}
|
||||
res, err := s.db.ExecContext(ctx, `UPDATE tenants SET payment_overdue_since = ?, updated_at = ? WHERE id = ?`,
|
||||
v, formatTime(s.now()), id)
|
||||
return requireAffected(res, err, "Mandant "+id)
|
||||
}
|
||||
|
||||
// DeleteTenant löscht den Mandanten samt seiner Knoten und Tokens.
|
||||
func (s *Store) DeleteTenant(ctx context.Context, id string) error {
|
||||
res, err := s.db.ExecContext(ctx, `DELETE FROM tenants WHERE id = ?`, id)
|
||||
|
||||
Reference in new issue
Block a user