- Rename Go module switchboard-core → armature (155+ files) - Rename Docker image → gobha/armature - Rename K8s resources, secrets, deployments - Rename Prometheus metrics switchboard_* → armature_* - Rename env vars SWITCHBOARD_ADMIN_* → ARMATURE_ADMIN_* - Rename DB names switchboard_core* → armature* - Update all frontend branding, notification templates, docs - Update CI scripts, e2e tests, Keycloak realm, nginx conf - Rename scripts/switchboard-ca.sh → scripts/armature-ca.sh - Rename k8s/switchboard.yaml → k8s/armature.yaml - Rename chart alerting/dashboard files - Fix: DockerHub push uses env: binding for secret injection - Helm chart updated (name, labels, template functions, dashboard, alerting) - Replace favicon/icon assets with Armature brand No functional changes. Pure mechanical rename + CI fix. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
217 lines
6.8 KiB
Go
217 lines
6.8 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"armature/database"
|
|
"armature/models"
|
|
"armature/store"
|
|
)
|
|
|
|
type ScheduledTaskStore struct{}
|
|
|
|
func NewScheduledTaskStore() *ScheduledTaskStore {
|
|
return &ScheduledTaskStore{}
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) Create(ctx context.Context, t *models.ScheduledTask) error {
|
|
t.ID = uuid.New().String()
|
|
now := time.Now().UTC().Format(time.RFC3339)
|
|
t.CreatedAt, _ = time.Parse(time.RFC3339, now)
|
|
t.UpdatedAt = t.CreatedAt
|
|
|
|
params, _ := json.Marshal(t.TemplateParams)
|
|
if len(params) == 0 {
|
|
params = []byte("{}")
|
|
}
|
|
|
|
var nextFire *string
|
|
if t.NextFireAt != nil {
|
|
s := t.NextFireAt.UTC().Format(time.RFC3339)
|
|
nextFire = &s
|
|
}
|
|
|
|
_, err := DB.ExecContext(ctx,
|
|
`INSERT INTO scheduled_tasks (id, name, description, creator_id, run_as, cron_expr,
|
|
next_fire_at, enabled, script, template_id, template_params, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
t.ID, t.Name, t.Description, t.CreatorID, t.RunAs, t.CronExpr,
|
|
nextFire, boolToInt(t.Enabled), t.Script,
|
|
nullIfEmpty(t.TemplateID), string(params), now, now)
|
|
return err
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) GetByID(ctx context.Context, id string) (*models.ScheduledTask, error) {
|
|
var t models.ScheduledTask
|
|
var paramsStr string
|
|
err := DB.QueryRowContext(ctx,
|
|
`SELECT id, name, description, creator_id, run_as, cron_expr,
|
|
next_fire_at, last_fire_at, enabled, script,
|
|
COALESCE(template_id,''), template_params, fire_count,
|
|
COALESCE(last_error,''), last_duration_ms, created_at, updated_at
|
|
FROM scheduled_tasks WHERE id = ?`, id).
|
|
Scan(&t.ID, &t.Name, &t.Description, &t.CreatorID, &t.RunAs, &t.CronExpr,
|
|
database.SNT(&t.NextFireAt), database.SNT(&t.LastFireAt),
|
|
&t.Enabled, &t.Script,
|
|
&t.TemplateID, ¶msStr, &t.FireCount,
|
|
&t.LastError, &t.LastDurationMs,
|
|
database.ST(&t.CreatedAt), database.ST(&t.UpdatedAt))
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.TemplateParams = json.RawMessage(paramsStr)
|
|
return &t, nil
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) Update(ctx context.Context, t *models.ScheduledTask) error {
|
|
params, _ := json.Marshal(t.TemplateParams)
|
|
if len(params) == 0 {
|
|
params = []byte("{}")
|
|
}
|
|
var nextFire *string
|
|
if t.NextFireAt != nil {
|
|
s := t.NextFireAt.UTC().Format(time.RFC3339)
|
|
nextFire = &s
|
|
}
|
|
_, err := DB.ExecContext(ctx,
|
|
`UPDATE scheduled_tasks SET name = ?, description = ?, run_as = ?,
|
|
cron_expr = ?, next_fire_at = ?, enabled = ?, script = ?,
|
|
template_id = ?, template_params = ?, updated_at = datetime('now')
|
|
WHERE id = ?`,
|
|
t.Name, t.Description, t.RunAs, t.CronExpr, nextFire,
|
|
boolToInt(t.Enabled), t.Script,
|
|
nullIfEmpty(t.TemplateID), string(params), t.ID)
|
|
return err
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) Delete(ctx context.Context, id string) error {
|
|
_, err := DB.ExecContext(ctx, `DELETE FROM scheduled_tasks WHERE id = ?`, id)
|
|
return err
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) List(ctx context.Context, opts store.ScheduledTaskListOptions) ([]models.ScheduledTask, int, error) {
|
|
where := "1=1"
|
|
args := []any{}
|
|
|
|
if opts.CreatorID != "" {
|
|
where += " AND creator_id = ?"
|
|
args = append(args, opts.CreatorID)
|
|
}
|
|
if opts.Enabled != nil {
|
|
where += " AND enabled = ?"
|
|
args = append(args, boolToInt(*opts.Enabled))
|
|
}
|
|
|
|
var total int
|
|
countArgs := make([]any, len(args))
|
|
copy(countArgs, args)
|
|
err := DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM scheduled_tasks WHERE "+where, countArgs...).Scan(&total)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
limit := opts.Limit
|
|
if limit <= 0 {
|
|
limit = 50
|
|
}
|
|
query := fmt.Sprintf(
|
|
`SELECT id, name, description, creator_id, run_as, cron_expr,
|
|
next_fire_at, last_fire_at, enabled, script,
|
|
COALESCE(template_id,''), template_params, fire_count,
|
|
COALESCE(last_error,''), last_duration_ms, created_at, updated_at
|
|
FROM scheduled_tasks WHERE %s ORDER BY created_at DESC LIMIT ? OFFSET ?`, where)
|
|
args = append(args, limit, opts.Offset)
|
|
|
|
rows, err := DB.QueryContext(ctx, query, args...)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
tasks, err := scanScheduledTaskRowsSqlite(rows)
|
|
return tasks, total, err
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) ListByCreator(ctx context.Context, creatorID string) ([]models.ScheduledTask, error) {
|
|
rows, err := DB.QueryContext(ctx,
|
|
`SELECT id, name, description, creator_id, run_as, cron_expr,
|
|
next_fire_at, last_fire_at, enabled, script,
|
|
COALESCE(template_id,''), template_params, fire_count,
|
|
COALESCE(last_error,''), last_duration_ms, created_at, updated_at
|
|
FROM scheduled_tasks WHERE creator_id = ? ORDER BY created_at DESC`, creatorID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
return scanScheduledTaskRowsSqlite(rows)
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) ListEnabled(ctx context.Context) ([]models.ScheduledTask, error) {
|
|
rows, err := DB.QueryContext(ctx,
|
|
`SELECT id, name, description, creator_id, run_as, cron_expr,
|
|
next_fire_at, last_fire_at, enabled, script,
|
|
COALESCE(template_id,''), template_params, fire_count,
|
|
COALESCE(last_error,''), last_duration_ms, created_at, updated_at
|
|
FROM scheduled_tasks WHERE enabled = 1 ORDER BY created_at`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
return scanScheduledTaskRowsSqlite(rows)
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) SetEnabled(ctx context.Context, id string, enabled bool) error {
|
|
_, err := DB.ExecContext(ctx,
|
|
`UPDATE scheduled_tasks SET enabled = ?, updated_at = datetime('now') WHERE id = ?`,
|
|
boolToInt(enabled), id)
|
|
return err
|
|
}
|
|
|
|
func (s *ScheduledTaskStore) UpdateFireState(ctx context.Context, id string, lastFireAt time.Time, nextFireAt *time.Time, lastError string, durationMs int) error {
|
|
var nextFire *string
|
|
if nextFireAt != nil {
|
|
s := nextFireAt.UTC().Format(time.RFC3339)
|
|
nextFire = &s
|
|
}
|
|
_, err := DB.ExecContext(ctx,
|
|
`UPDATE scheduled_tasks SET last_fire_at = ?, next_fire_at = ?,
|
|
last_error = ?, last_duration_ms = ?, fire_count = fire_count + 1,
|
|
updated_at = datetime('now') WHERE id = ?`,
|
|
lastFireAt.UTC().Format(time.RFC3339), nextFire,
|
|
nullIfEmpty(lastError), durationMs, id)
|
|
return err
|
|
}
|
|
|
|
// ── Helpers ──────────────────────────────────
|
|
|
|
func scanScheduledTaskRowsSqlite(rows *sql.Rows) ([]models.ScheduledTask, error) {
|
|
var tasks []models.ScheduledTask
|
|
for rows.Next() {
|
|
var t models.ScheduledTask
|
|
var paramsStr string
|
|
if err := rows.Scan(&t.ID, &t.Name, &t.Description, &t.CreatorID, &t.RunAs,
|
|
&t.CronExpr, database.SNT(&t.NextFireAt), database.SNT(&t.LastFireAt),
|
|
&t.Enabled, &t.Script,
|
|
&t.TemplateID, ¶msStr, &t.FireCount,
|
|
&t.LastError, &t.LastDurationMs,
|
|
database.ST(&t.CreatedAt), database.ST(&t.UpdatedAt)); err != nil {
|
|
return nil, err
|
|
}
|
|
t.TemplateParams = json.RawMessage(paramsStr)
|
|
tasks = append(tasks, t)
|
|
}
|
|
if tasks == nil {
|
|
tasks = []models.ScheduledTask{}
|
|
}
|
|
return tasks, nil
|
|
}
|