1package storage
2
3import (
4 "context"
5 "database/sql"
6 "encoding/json"
7 "errors"
8 "fmt"
9 "time"
10)
11
12func (s *Store) UpdateOwnDisplayNameAudited(ctx context.Context, userID, displayName string, audit AppendAuditInput) error {
13 return s.UpdateOwnDisplayNameAuditedAt(ctx, userID, displayName, audit, s.now())
14}
15
16func (s *Store) UpdateOwnDisplayNameAuditedAt(ctx context.Context, userID, displayName string, audit AppendAuditInput, now time.Time) error {
17 const operation = "update own display name"
18 if err := validateDisplayName(displayName); err != nil {
19 return invalid(operation, err)
20 }
21 fields := map[string]any{}
22 if audit.Detail != "" {
23 if err := json.Unmarshal([]byte(audit.Detail), &fields); err != nil || fields == nil {
24 return invalid(operation, fmt.Errorf("audit detail is not a JSON object"))
25 }
26 }
27 return s.auditedAt(ctx, operation, audit.Actor, now, func(tx *sql.Tx, at time.Time) error {
28 var username, current string
29 var disabled int
30 err := tx.QueryRowContext(ctx, `SELECT username, display_name, disabled FROM users WHERE id = ?`, userID).Scan(&username, ¤t, &disabled)
31 switch {
32 case errors.Is(err, sql.ErrNoRows):
33 return fmt.Errorf("%s: %w", operation, ErrNotFound)
34 case err != nil:
35 return classify(operation, err)
36 case disabled != 0:
37 return fmt.Errorf("%s: %w: the user is disabled", operation, ErrNotFound)
38 }
39 if _, err := tx.ExecContext(ctx, `UPDATE users SET display_name = ? WHERE id = ?`, displayName, userID); err != nil {
40 return classify(operation, err)
41 }
42 fields["username"] = username
43 fields["display_name_changed"] = current != displayName
44 return writeAudit(ctx, tx, operation, audit.Actor, audit.Action, audit.Subject, at, fields)
45 })
46}