Add polished answer notifications (#1)
Sends a branded Resend email when a question receives its first answer, records accepted and failed sends, and adds collapsed answer editing with cancel behavior. Co-authored-by: codegirl-007 <s.raide@gmail.com>
This commit was merged in pull request #1.
This commit is contained in:
+18
-8
@@ -30,6 +30,7 @@ type User struct {
|
||||
Username string
|
||||
Name string
|
||||
Role Role
|
||||
Email string
|
||||
AvatarURL string
|
||||
State string
|
||||
CreatedAt string
|
||||
@@ -50,12 +51,13 @@ func NormalizeUsername(s string) string {
|
||||
return strings.ToLower(strings.TrimSpace(s))
|
||||
}
|
||||
|
||||
func toUser(db *sql.DB, id, username, name, role, avatarURL, state, createdAt, passwordHash string) *User {
|
||||
func toUser(db *sql.DB, id, username, name, role, email, avatarURL, state, createdAt, passwordHash string) *User {
|
||||
return &User{
|
||||
ID: id,
|
||||
Username: username,
|
||||
Name: name,
|
||||
Role: Role(role),
|
||||
Email: email,
|
||||
AvatarURL: avatarURL,
|
||||
State: state,
|
||||
CreatedAt: createdAt,
|
||||
@@ -73,6 +75,7 @@ func (u *User) Create(ctx context.Context) error {
|
||||
return fmt.Errorf("invalid role")
|
||||
}
|
||||
u.Username = NormalizeUsername(u.Username)
|
||||
u.Email = NormalizeEmail(u.Email)
|
||||
if u.ID == "" {
|
||||
u.ID = uuid.NewString()
|
||||
}
|
||||
@@ -88,6 +91,7 @@ func (u *User) Create(ctx context.Context) error {
|
||||
Name: u.Name,
|
||||
PasswordHash: u.PasswordHash,
|
||||
Role: string(u.Role),
|
||||
Email: u.Email,
|
||||
CreatedAt: u.CreatedAt,
|
||||
}))
|
||||
}
|
||||
@@ -149,21 +153,27 @@ func (u *User) SetRole(ctx context.Context, role Role) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveProfile writes State and optionally AvatarURL.
|
||||
// SaveProfile writes Email, State, and optionally AvatarURL.
|
||||
func (u *User) SaveProfile(ctx context.Context) error {
|
||||
if u == nil || u.db == nil {
|
||||
return fmt.Errorf("user: no database")
|
||||
}
|
||||
u.State = strings.TrimSpace(u.State)
|
||||
u.Email = NormalizeEmail(u.Email)
|
||||
q := sqlc.New(u.db)
|
||||
if u.AvatarURL == "" {
|
||||
return q.UpdateUserState(ctx, sqlc.UpdateUserStateParams{State: u.State, ID: u.ID})
|
||||
return mapUniqueViolation(q.UpdateUserProfile(ctx, sqlc.UpdateUserProfileParams{
|
||||
State: u.State,
|
||||
Email: u.Email,
|
||||
ID: u.ID,
|
||||
}))
|
||||
}
|
||||
return q.UpdateUserStateAndAvatar(ctx, sqlc.UpdateUserStateAndAvatarParams{
|
||||
return mapUniqueViolation(q.UpdateUserProfileAndAvatar(ctx, sqlc.UpdateUserProfileAndAvatarParams{
|
||||
State: u.State,
|
||||
Email: u.Email,
|
||||
AvatarUrl: u.AvatarURL,
|
||||
ID: u.ID,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
func CountAdmins(ctx context.Context, db *sql.DB) (int, error) {
|
||||
@@ -187,7 +197,7 @@ func ListUsers(ctx context.Context, db *sql.DB, q ListUsersQuery) ([]User, strin
|
||||
}
|
||||
out := make([]User, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
u := toUser(db, r.ID, r.Username, r.Name, r.Role, r.AvatarUrl, r.State, r.CreatedAt, "")
|
||||
u := toUser(db, r.ID, r.Username, r.Name, r.Role, r.Email, r.AvatarUrl, r.State, r.CreatedAt, "")
|
||||
out = append(out, *u)
|
||||
}
|
||||
var nextCreated, nextID string
|
||||
@@ -204,7 +214,7 @@ func UserByID(ctx context.Context, db *sql.DB, id string) (*User, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toUser(db, r.ID, r.Username, r.Name, r.Role, r.AvatarUrl, r.State, r.CreatedAt, ""), nil
|
||||
return toUser(db, r.ID, r.Username, r.Name, r.Role, r.Email, r.AvatarUrl, r.State, r.CreatedAt, ""), nil
|
||||
}
|
||||
|
||||
func UserByUsername(ctx context.Context, db *sql.DB, username string) (*User, error) {
|
||||
@@ -212,5 +222,5 @@ func UserByUsername(ctx context.Context, db *sql.DB, username string) (*User, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toUser(db, r.ID, r.Username, r.Name, r.Role, r.AvatarUrl, r.State, r.CreatedAt, r.PasswordHash), nil
|
||||
return toUser(db, r.ID, r.Username, r.Name, r.Role, r.Email, r.AvatarUrl, r.State, r.CreatedAt, r.PasswordHash), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user