This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/store/sqlite/notification.go
Jeffrey Smith f0dd43144e rebrand: Switchboard Core → Armature
- 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>
2026-03-31 21:39:58 +00:00

147 lines
3.6 KiB
Go

package sqlite
import (
"context"
"database/sql"
"time"
"armature/models"
"armature/store"
)
type NotificationStore struct{}
func NewNotificationStore() *NotificationStore { return &NotificationStore{} }
func (s *NotificationStore) Create(ctx context.Context, n *models.Notification) error {
if n.ID == "" {
n.ID = store.NewID()
}
now := time.Now().UTC().Format(timeFmt)
_, err := DB.ExecContext(ctx, `
INSERT INTO notifications (id, user_id, type, title, body, resource_type, resource_id, is_read, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
n.ID, n.UserID, n.Type, n.Title, n.Body,
nullStr(n.ResourceType), nullStr(n.ResourceID), boolToInt(n.IsRead), now,
)
if err != nil {
return err
}
n.CreatedAt, _ = time.Parse(timeFmt, now)
return nil
}
func (s *NotificationStore) ListByUser(ctx context.Context, userID string, limit, offset int, unreadOnly bool) ([]models.Notification, int, error) {
if limit <= 0 {
limit = 20
}
// Count
countQ := `SELECT COUNT(*) FROM notifications WHERE user_id = ?`
countArgs := []interface{}{userID}
if unreadOnly {
countQ += ` AND is_read = 0`
}
var total int
if err := DB.QueryRowContext(ctx, countQ, countArgs...).Scan(&total); err != nil {
return nil, 0, err
}
// Fetch
q := `SELECT id, user_id, type, title, body, resource_type, resource_id, is_read, created_at
FROM notifications WHERE user_id = ?`
if unreadOnly {
q += ` AND is_read = 0`
}
q += ` ORDER BY created_at DESC LIMIT ? OFFSET ?`
rows, err := DB.QueryContext(ctx, q, userID, limit, offset)
if err != nil {
return nil, 0, err
}
defer rows.Close()
var items []models.Notification
for rows.Next() {
var n models.Notification
var resType, resID sql.NullString
var isRead int
if err := rows.Scan(
&n.ID, &n.UserID, &n.Type, &n.Title, &n.Body,
&resType, &resID, &isRead, st(&n.CreatedAt),
); err != nil {
return nil, 0, err
}
n.ResourceType = NullableString(resType)
n.ResourceID = NullableString(resID)
n.IsRead = isRead != 0
items = append(items, n)
}
if items == nil {
items = []models.Notification{}
}
return items, total, rows.Err()
}
func (s *NotificationStore) MarkRead(ctx context.Context, id, userID string) error {
res, err := DB.ExecContext(ctx,
`UPDATE notifications SET is_read = 1 WHERE id = ? AND user_id = ?`,
id, userID)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n == 0 {
return sql.ErrNoRows
}
return nil
}
func (s *NotificationStore) MarkAllRead(ctx context.Context, userID string) error {
_, err := DB.ExecContext(ctx,
`UPDATE notifications SET is_read = 1 WHERE user_id = ? AND is_read = 0`,
userID)
return err
}
func (s *NotificationStore) Delete(ctx context.Context, id, userID string) error {
res, err := DB.ExecContext(ctx,
`DELETE FROM notifications WHERE id = ? AND user_id = ?`, id, userID)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n == 0 {
return sql.ErrNoRows
}
return nil
}
func (s *NotificationStore) UnreadCount(ctx context.Context, userID string) (int, error) {
var count int
err := DB.QueryRowContext(ctx,
`SELECT COUNT(*) FROM notifications WHERE user_id = ? AND is_read = 0`,
userID).Scan(&count)
return count, err
}
func (s *NotificationStore) DeleteOlderThan(ctx context.Context, before time.Time) (int64, error) {
res, err := DB.ExecContext(ctx,
`DELETE FROM notifications WHERE created_at < ?`,
before.UTC().Format(timeFmt))
if err != nil {
return 0, err
}
return res.RowsAffected()
}
// nullStr returns sql.NullString for optional string fields.
func nullStr(s string) sql.NullString {
if s == "" {
return sql.NullString{}
}
return sql.NullString{String: s, Valid: true}
}