Changeset 0.29.0 (#195)

This commit is contained in:
2026-03-17 16:28:47 +00:00
parent 128cbb8174
commit 5d637d3a90
129 changed files with 9418 additions and 3016 deletions

View File

@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"git.gobha.me/xcaliber/chat-switchboard/models"
@@ -193,3 +194,110 @@ func (s *UserStore) scanOne(ctx context.Context, query string, args ...interface
ScanJSON(sj, &u.Settings)
return &u, nil
}
// ── CS1 additions (v0.29.0) ─────────────────────────────────────────────
func (s *UserStore) Exists(ctx context.Context, userID string) (bool, error) {
var count int
err := DB.QueryRowContext(ctx,
`SELECT COUNT(*) FROM users WHERE id = ?`, userID).Scan(&count)
return count > 0, err
}
func (s *UserStore) SearchActive(ctx context.Context, excludeUserID, query string) ([]store.UserSearchResult, error) {
q := `
SELECT id, username, COALESCE(display_name, '') AS display_name, COALESCE(handle, '') AS handle
FROM users
WHERE is_active = 1 AND id != ?`
args := []interface{}{excludeUserID}
if query != "" {
q += ` AND (LOWER(username) LIKE ? OR LOWER(display_name) LIKE ? OR LOWER(handle) LIKE ?)`
pattern := "%" + strings.ToLower(query) + "%"
args = append(args, pattern, pattern, pattern)
}
q += ` ORDER BY username LIMIT 20`
rows, err := DB.QueryContext(ctx, q, args...)
if err != nil {
return nil, err
}
defer rows.Close()
var results []store.UserSearchResult
for rows.Next() {
var u store.UserSearchResult
if err := rows.Scan(&u.ID, &u.Username, &u.DisplayName, &u.Handle); err != nil {
continue
}
results = append(results, u)
}
if results == nil {
results = []store.UserSearchResult{}
}
return results, rows.Err()
}
// ── CS2 additions (v0.29.0) ─────────────────────────────────────────────
func (s *UserStore) CountByRole(ctx context.Context, role string) (int, error) {
var count int
err := DB.QueryRowContext(ctx,
`SELECT COUNT(*) FROM users WHERE role = ?`, role).Scan(&count)
return count, err
}
func (s *UserStore) MergeSettings(ctx context.Context, userID string, patch []byte) error {
_, err := DB.ExecContext(ctx, `
UPDATE users SET settings = json_patch(
CASE WHEN settings IS NULL OR settings = 'null' OR json_type(settings) != 'object'
THEN '{}' ELSE settings END,
?), updated_at = datetime('now') WHERE id = ?
`, string(patch), userID)
return err
}
func (s *UserStore) GetVaultKeys(ctx context.Context, userID string) (bool, []byte, []byte, []byte, error) {
var vaultSet bool
var encUEK, salt, nonce []byte
err := DB.QueryRowContext(ctx, `
SELECT vault_set, encrypted_uek, uek_salt, uek_nonce
FROM users WHERE id = ?
`, userID).Scan(&vaultSet, &encUEK, &salt, &nonce)
return vaultSet, encUEK, salt, nonce, err
}
func (s *UserStore) UpdateVaultKeys(ctx context.Context, userID string, encUEK, salt, nonce []byte) error {
_, err := DB.ExecContext(ctx, `
UPDATE users
SET encrypted_uek = ?, uek_salt = ?, uek_nonce = ?, updated_at = datetime('now')
WHERE id = ?
`, encUEK, salt, nonce, userID)
return err
}
func (s *UserStore) CountAll(ctx context.Context) (int, error) {
var count int
err := DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM users").Scan(&count)
return count, err
}
// ── CS4 additions (v0.29.0) ─────────────────────────────────────────────
func (s *UserStore) ClearVaultKeys(ctx context.Context, userID string) error {
_, err := DB.ExecContext(ctx, `
UPDATE users
SET encrypted_uek = NULL, uek_salt = NULL, uek_nonce = NULL, vault_set = 0
WHERE id = ?
`, userID)
return err
}
func (s *UserStore) InitVaultKeys(ctx context.Context, userID string, encUEK, salt, nonce []byte) error {
_, err := DB.ExecContext(ctx, `
UPDATE users
SET encrypted_uek = ?, uek_salt = ?, uek_nonce = ?, vault_set = 1
WHERE id = ?
`, encUEK, salt, nonce, userID)
return err
}