mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add notification preferences database & audit support (#14100)
This commit is contained in:
+172
-12
@@ -3335,14 +3335,18 @@ SELECT
|
||||
nm.id,
|
||||
nm.payload,
|
||||
nm.method,
|
||||
nm.attempt_count::int AS attempt_count,
|
||||
nm.queued_seconds::float AS queued_seconds,
|
||||
nm.attempt_count::int AS attempt_count,
|
||||
nm.queued_seconds::float AS queued_seconds,
|
||||
-- template
|
||||
nt.id AS template_id,
|
||||
nt.id AS template_id,
|
||||
nt.title_template,
|
||||
nt.body_template
|
||||
nt.body_template,
|
||||
-- preferences
|
||||
(CASE WHEN np.disabled IS NULL THEN false ELSE np.disabled END)::bool AS disabled
|
||||
FROM acquired nm
|
||||
JOIN notification_templates nt ON nm.notification_template_id = nt.id
|
||||
LEFT JOIN notification_preferences AS np
|
||||
ON (np.user_id = nm.user_id AND np.notification_template_id = nm.notification_template_id)
|
||||
`
|
||||
|
||||
type AcquireNotificationMessagesParams struct {
|
||||
@@ -3361,6 +3365,7 @@ type AcquireNotificationMessagesRow struct {
|
||||
TemplateID uuid.UUID `db:"template_id" json:"template_id"`
|
||||
TitleTemplate string `db:"title_template" json:"title_template"`
|
||||
BodyTemplate string `db:"body_template" json:"body_template"`
|
||||
Disabled bool `db:"disabled" json:"disabled"`
|
||||
}
|
||||
|
||||
// Acquires the lease for a given count of notification messages, to enable concurrent dequeuing and subsequent sending.
|
||||
@@ -3396,6 +3401,7 @@ func (q *sqlQuerier) AcquireNotificationMessages(ctx context.Context, arg Acquir
|
||||
&i.TemplateID,
|
||||
&i.TitleTemplate,
|
||||
&i.BodyTemplate,
|
||||
&i.Disabled,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -3534,10 +3540,11 @@ func (q *sqlQuerier) EnqueueNotificationMessage(ctx context.Context, arg Enqueue
|
||||
const fetchNewMessageMetadata = `-- name: FetchNewMessageMetadata :one
|
||||
SELECT nt.name AS notification_name,
|
||||
nt.actions AS actions,
|
||||
nt.method AS custom_method,
|
||||
u.id AS user_id,
|
||||
u.email AS user_email,
|
||||
COALESCE(NULLIF(u.name, ''), NULLIF(u.username, ''))::text AS user_name,
|
||||
COALESCE(u.username, '') AS user_username
|
||||
u.username AS user_username
|
||||
FROM notification_templates nt,
|
||||
users u
|
||||
WHERE nt.id = $1
|
||||
@@ -3550,12 +3557,13 @@ type FetchNewMessageMetadataParams struct {
|
||||
}
|
||||
|
||||
type FetchNewMessageMetadataRow struct {
|
||||
NotificationName string `db:"notification_name" json:"notification_name"`
|
||||
Actions []byte `db:"actions" json:"actions"`
|
||||
UserID uuid.UUID `db:"user_id" json:"user_id"`
|
||||
UserEmail string `db:"user_email" json:"user_email"`
|
||||
UserName string `db:"user_name" json:"user_name"`
|
||||
UserUsername string `db:"user_username" json:"user_username"`
|
||||
NotificationName string `db:"notification_name" json:"notification_name"`
|
||||
Actions []byte `db:"actions" json:"actions"`
|
||||
CustomMethod NullNotificationMethod `db:"custom_method" json:"custom_method"`
|
||||
UserID uuid.UUID `db:"user_id" json:"user_id"`
|
||||
UserEmail string `db:"user_email" json:"user_email"`
|
||||
UserName string `db:"user_name" json:"user_name"`
|
||||
UserUsername string `db:"user_username" json:"user_username"`
|
||||
}
|
||||
|
||||
// This is used to build up the notification_message's JSON payload.
|
||||
@@ -3565,6 +3573,7 @@ func (q *sqlQuerier) FetchNewMessageMetadata(ctx context.Context, arg FetchNewMe
|
||||
err := row.Scan(
|
||||
&i.NotificationName,
|
||||
&i.Actions,
|
||||
&i.CustomMethod,
|
||||
&i.UserID,
|
||||
&i.UserEmail,
|
||||
&i.UserName,
|
||||
@@ -3574,7 +3583,10 @@ func (q *sqlQuerier) FetchNewMessageMetadata(ctx context.Context, arg FetchNewMe
|
||||
}
|
||||
|
||||
const getNotificationMessagesByStatus = `-- name: GetNotificationMessagesByStatus :many
|
||||
SELECT id, notification_template_id, user_id, method, status, status_reason, created_by, payload, attempt_count, targets, created_at, updated_at, leased_until, next_retry_after, queued_seconds FROM notification_messages WHERE status = $1 LIMIT $2::int
|
||||
SELECT id, notification_template_id, user_id, method, status, status_reason, created_by, payload, attempt_count, targets, created_at, updated_at, leased_until, next_retry_after, queued_seconds
|
||||
FROM notification_messages
|
||||
WHERE status = $1
|
||||
LIMIT $2::int
|
||||
`
|
||||
|
||||
type GetNotificationMessagesByStatusParams struct {
|
||||
@@ -3621,6 +3633,154 @@ func (q *sqlQuerier) GetNotificationMessagesByStatus(ctx context.Context, arg Ge
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getNotificationTemplateByID = `-- name: GetNotificationTemplateByID :one
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind
|
||||
FROM notification_templates
|
||||
WHERE id = $1::uuid
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetNotificationTemplateByID(ctx context.Context, id uuid.UUID) (NotificationTemplate, error) {
|
||||
row := q.db.QueryRowContext(ctx, getNotificationTemplateByID, id)
|
||||
var i NotificationTemplate
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.TitleTemplate,
|
||||
&i.BodyTemplate,
|
||||
&i.Actions,
|
||||
&i.Group,
|
||||
&i.Method,
|
||||
&i.Kind,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getNotificationTemplatesByKind = `-- name: GetNotificationTemplatesByKind :many
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind
|
||||
FROM notification_templates
|
||||
WHERE kind = $1::notification_template_kind
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetNotificationTemplatesByKind(ctx context.Context, kind NotificationTemplateKind) ([]NotificationTemplate, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getNotificationTemplatesByKind, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []NotificationTemplate
|
||||
for rows.Next() {
|
||||
var i NotificationTemplate
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.TitleTemplate,
|
||||
&i.BodyTemplate,
|
||||
&i.Actions,
|
||||
&i.Group,
|
||||
&i.Method,
|
||||
&i.Kind,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getUserNotificationPreferences = `-- name: GetUserNotificationPreferences :many
|
||||
SELECT user_id, notification_template_id, disabled, created_at, updated_at
|
||||
FROM notification_preferences
|
||||
WHERE user_id = $1::uuid
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetUserNotificationPreferences(ctx context.Context, userID uuid.UUID) ([]NotificationPreference, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getUserNotificationPreferences, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []NotificationPreference
|
||||
for rows.Next() {
|
||||
var i NotificationPreference
|
||||
if err := rows.Scan(
|
||||
&i.UserID,
|
||||
&i.NotificationTemplateID,
|
||||
&i.Disabled,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateNotificationTemplateMethodByID = `-- name: UpdateNotificationTemplateMethodByID :one
|
||||
UPDATE notification_templates
|
||||
SET method = $1::notification_method
|
||||
WHERE id = $2::uuid
|
||||
RETURNING id, name, title_template, body_template, actions, "group", method, kind
|
||||
`
|
||||
|
||||
type UpdateNotificationTemplateMethodByIDParams struct {
|
||||
Method NullNotificationMethod `db:"method" json:"method"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateNotificationTemplateMethodByID(ctx context.Context, arg UpdateNotificationTemplateMethodByIDParams) (NotificationTemplate, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateNotificationTemplateMethodByID, arg.Method, arg.ID)
|
||||
var i NotificationTemplate
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.TitleTemplate,
|
||||
&i.BodyTemplate,
|
||||
&i.Actions,
|
||||
&i.Group,
|
||||
&i.Method,
|
||||
&i.Kind,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserNotificationPreferences = `-- name: UpdateUserNotificationPreferences :execrows
|
||||
INSERT
|
||||
INTO notification_preferences (user_id, notification_template_id, disabled)
|
||||
SELECT $1::uuid, new_values.notification_template_id, new_values.disabled
|
||||
FROM (SELECT UNNEST($2::uuid[]) AS notification_template_id,
|
||||
UNNEST($3::bool[]) AS disabled) AS new_values
|
||||
ON CONFLICT (user_id, notification_template_id) DO UPDATE
|
||||
SET disabled = EXCLUDED.disabled,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
`
|
||||
|
||||
type UpdateUserNotificationPreferencesParams struct {
|
||||
UserID uuid.UUID `db:"user_id" json:"user_id"`
|
||||
NotificationTemplateIds []uuid.UUID `db:"notification_template_ids" json:"notification_template_ids"`
|
||||
Disableds []bool `db:"disableds" json:"disableds"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateUserNotificationPreferences(ctx context.Context, arg UpdateUserNotificationPreferencesParams) (int64, error) {
|
||||
result, err := q.db.ExecContext(ctx, updateUserNotificationPreferences, arg.UserID, pq.Array(arg.NotificationTemplateIds), pq.Array(arg.Disableds))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
const deleteOAuth2ProviderAppByID = `-- name: DeleteOAuth2ProviderAppByID :exec
|
||||
DELETE FROM oauth2_provider_apps WHERE id = $1
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user