Stage 10: admin console & dictionary ops (complaint review, hot-reload, broadcasts) (#11)
This commit was merged in pull request #11.
This commit is contained in:
@@ -67,6 +67,16 @@ type Account struct {
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Identity is one of an account's platform/email identities, surfaced on the
|
||||
// admin account-detail view. ExternalID is the platform user id (or the email
|
||||
// address for an email identity); Confirmed tracks the email confirm-code flow.
|
||||
type Identity struct {
|
||||
Kind string
|
||||
ExternalID string
|
||||
Confirmed bool
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// Store is the Postgres-backed query surface for accounts and identities.
|
||||
type Store struct {
|
||||
db *sql.DB
|
||||
@@ -187,6 +197,54 @@ func (s *Store) IdentityExternalID(ctx context.Context, accountID uuid.UUID, kin
|
||||
return row.ExternalID, nil
|
||||
}
|
||||
|
||||
// Identities returns the account's platform/email identities, oldest first, for
|
||||
// the admin account-detail view.
|
||||
func (s *Store) Identities(ctx context.Context, accountID uuid.UUID) ([]Identity, error) {
|
||||
stmt := postgres.SELECT(table.Identities.AllColumns).
|
||||
FROM(table.Identities).
|
||||
WHERE(table.Identities.AccountID.EQ(postgres.UUID(accountID))).
|
||||
ORDER_BY(table.Identities.CreatedAt.ASC())
|
||||
var rows []model.Identities
|
||||
if err := stmt.QueryContext(ctx, s.db, &rows); err != nil {
|
||||
return nil, fmt.Errorf("account: list identities %s: %w", accountID, err)
|
||||
}
|
||||
out := make([]Identity, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
out = append(out, Identity{Kind: r.Kind, ExternalID: r.ExternalID, Confirmed: r.Confirmed, CreatedAt: r.CreatedAt})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ListAccounts returns accounts for the admin user list, newest first, paginated
|
||||
// by limit and offset.
|
||||
func (s *Store) ListAccounts(ctx context.Context, limit, offset int) ([]Account, error) {
|
||||
stmt := postgres.SELECT(table.Accounts.AllColumns).
|
||||
FROM(table.Accounts).
|
||||
ORDER_BY(table.Accounts.CreatedAt.DESC()).
|
||||
LIMIT(int64(limit)).
|
||||
OFFSET(int64(offset))
|
||||
var rows []model.Accounts
|
||||
if err := stmt.QueryContext(ctx, s.db, &rows); err != nil {
|
||||
return nil, fmt.Errorf("account: list accounts: %w", err)
|
||||
}
|
||||
out := make([]Account, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
out = append(out, modelToAccount(r))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CountAccounts returns the total number of accounts, for admin-list pagination.
|
||||
func (s *Store) CountAccounts(ctx context.Context) (int, error) {
|
||||
stmt := postgres.SELECT(postgres.COUNT(table.Accounts.AccountID).AS("count")).
|
||||
FROM(table.Accounts)
|
||||
var dest struct{ Count int64 }
|
||||
if err := stmt.QueryContext(ctx, s.db, &dest); err != nil {
|
||||
return 0, fmt.Errorf("account: count accounts: %w", err)
|
||||
}
|
||||
return int(dest.Count), nil
|
||||
}
|
||||
|
||||
// findByIdentity joins identities to accounts and returns the matching account,
|
||||
// or ErrNotFound.
|
||||
func (s *Store) findByIdentity(ctx context.Context, kind, externalID string) (Account, error) {
|
||||
|
||||
Reference in New Issue
Block a user