feat: add feedback acknowledgement
This commit is contained in:
@@ -37,12 +37,14 @@ func (r *FeedbackRepo) Create(ctx context.Context, userID *string, category, mes
|
||||
func (r *FeedbackRepo) FindByID(ctx context.Context, id string) (*model.Feedback, error) {
|
||||
f := &model.Feedback{}
|
||||
err := r.pg.Pool.QueryRow(ctx, `
|
||||
SELECT f.id, f.user_id, f.category, f.message, f.contact_email, f.created_at, f.resolved_at,
|
||||
SELECT f.id, f.user_id, f.category, f.message, f.contact_email, f.created_at,
|
||||
f.acknowledged_at, f.resolved_at,
|
||||
u.handle, u.name, u.email
|
||||
FROM feedback f
|
||||
LEFT JOIN users u ON u.id = f.user_id
|
||||
WHERE f.id = $1`, id,
|
||||
).Scan(&f.ID, &f.UserID, &f.Category, &f.Message, &f.ContactEmail, &f.CreatedAt, &f.ResolvedAt,
|
||||
).Scan(&f.ID, &f.UserID, &f.Category, &f.Message, &f.ContactEmail, &f.CreatedAt,
|
||||
&f.AcknowledgedAt, &f.ResolvedAt,
|
||||
&f.AuthorHandle, &f.AuthorName, &f.AuthorEmail)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("find feedback: %w", err)
|
||||
@@ -50,6 +52,22 @@ func (r *FeedbackRepo) FindByID(ctx context.Context, id string) (*model.Feedback
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// MarkAcknowledged stamps acknowledged_at = now() on a not-yet-
|
||||
// acknowledged row. The `acknowledged_at IS NULL` guard makes this
|
||||
// idempotent and one-way: first call returns true (newly acknowledged →
|
||||
// fire the email), any later call — or an unknown id — returns false.
|
||||
func (r *FeedbackRepo) MarkAcknowledged(ctx context.Context, id string) (acked bool, err error) {
|
||||
tag, err := r.pg.Pool.Exec(ctx, `
|
||||
UPDATE feedback
|
||||
SET acknowledged_at = now()
|
||||
WHERE id = $1 AND acknowledged_at IS NULL`, id,
|
||||
)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("mark feedback acknowledged: %w", err)
|
||||
}
|
||||
return tag.RowsAffected() == 1, nil
|
||||
}
|
||||
|
||||
// MarkResolved stamps resolved_at = now() on a still-open row. The
|
||||
// `resolved_at IS NULL` guard makes this idempotent and one-way: the
|
||||
// first call returns true (newly resolved), any subsequent call — or a
|
||||
@@ -75,7 +93,8 @@ func (r *FeedbackRepo) Recent(ctx context.Context, limit int) ([]model.Feedback,
|
||||
limit = 25
|
||||
}
|
||||
rows, err := r.pg.Pool.Query(ctx, `
|
||||
SELECT f.id, f.user_id, f.category, f.message, f.contact_email, f.created_at, f.resolved_at,
|
||||
SELECT f.id, f.user_id, f.category, f.message, f.contact_email, f.created_at,
|
||||
f.acknowledged_at, f.resolved_at,
|
||||
u.handle, u.name
|
||||
FROM feedback f
|
||||
LEFT JOIN users u ON u.id = f.user_id
|
||||
@@ -89,7 +108,8 @@ func (r *FeedbackRepo) Recent(ctx context.Context, limit int) ([]model.Feedback,
|
||||
out := []model.Feedback{}
|
||||
for rows.Next() {
|
||||
var f model.Feedback
|
||||
if err := rows.Scan(&f.ID, &f.UserID, &f.Category, &f.Message, &f.ContactEmail, &f.CreatedAt, &f.ResolvedAt,
|
||||
if err := rows.Scan(&f.ID, &f.UserID, &f.Category, &f.Message, &f.ContactEmail, &f.CreatedAt,
|
||||
&f.AcknowledgedAt, &f.ResolvedAt,
|
||||
&f.AuthorHandle, &f.AuthorName); err != nil {
|
||||
return nil, fmt.Errorf("scan feedback: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user