Raw
 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, &current, &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}