feat!: return user dto & create new rt on pw update
This commit is contained in:
parent
298aca465e
commit
0f3fef20e3
@ -178,10 +178,11 @@ func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]User, e
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updatePassword = `-- name: UpdatePassword :exec
|
||||
const updatePassword = `-- name: UpdatePassword :one
|
||||
UPDATE users
|
||||
SET password_hash = $2, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING id, username, password_hash, is_admin, created_at, updated_at
|
||||
`
|
||||
|
||||
type UpdatePasswordParams struct {
|
||||
@ -189,7 +190,16 @@ type UpdatePasswordParams struct {
|
||||
PasswordHash string `json:"password_hash"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error {
|
||||
_, err := q.db.Exec(ctx, updatePassword, arg.ID, arg.PasswordHash)
|
||||
return err
|
||||
func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) (User, error) {
|
||||
row := q.db.QueryRow(ctx, updatePassword, arg.ID, arg.PasswordHash)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.IsAdmin,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ type UserStore interface {
|
||||
ListUsers(ctx context.Context, arg data.ListUsersParams) ([]data.User, error)
|
||||
GetUserByID(ctx context.Context, id uuid.UUID) (data.User, error)
|
||||
GetUserByUsername(ctx context.Context, username string) (data.User, error)
|
||||
UpdatePassword(ctx context.Context, arg data.UpdatePasswordParams) error
|
||||
UpdatePassword(ctx context.Context, arg data.UpdatePasswordParams) (data.User, error)
|
||||
DeleteUser(ctx context.Context, id uuid.UUID) error
|
||||
RevokeAllUserRefreshTokens(ctx context.Context, id uuid.UUID) error
|
||||
}
|
||||
@ -271,7 +271,7 @@ func (rs authResource) Get(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Handler for updating the current user's password. Performs the same password strength checks as
|
||||
// the registration handler (`rs.Create`) and revokes any existing refresh tokens the user has
|
||||
// stored in the database.
|
||||
// stored in the database. The new access token and the updated user object's DTO will be returned.
|
||||
func (rs authResource) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
type request struct {
|
||||
OldPassword string `json:"old_password"`
|
||||
@ -306,19 +306,51 @@ func (rs authResource) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := rs.Users.UpdatePassword(r.Context(), data.UpdatePasswordParams{
|
||||
nUSer, err := rs.Users.UpdatePassword(r.Context(), data.UpdatePasswordParams{
|
||||
ID: user.ID,
|
||||
PasswordHash: string(hashedPassword),
|
||||
}); err != nil {
|
||||
})
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "Failed to update password")
|
||||
return
|
||||
}
|
||||
|
||||
// Revoke all old tokens before generating a new one for this session
|
||||
if err := rs.Users.RevokeAllUserRefreshTokens(r.Context(), user.ID); err != nil {
|
||||
log.Error().Msgf("Failed to revoke refresh tokens: %s", err)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
// Generate a new pair (access & refresh tokens)
|
||||
tokenPair, err := rs.GenerateTokenPair(r.Context(), user.ID, user.IsAdmin)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "Failed to generate tokens")
|
||||
return
|
||||
}
|
||||
|
||||
// Set refresh token into a httpOnly cookie
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "notatest.refresh_token",
|
||||
Value: tokenPair.RefreshToken,
|
||||
Path: "/api/auth/cookie",
|
||||
MaxAge: int(refreshTokenDuration.Seconds()),
|
||||
HttpOnly: true,
|
||||
Secure: rs.Config.IsProd,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
})
|
||||
|
||||
response := map[string]any{
|
||||
"access_token": tokenPair.AccessToken,
|
||||
"user": userResponse{
|
||||
ID: nUSer.ID,
|
||||
Username: nUSer.Username,
|
||||
IsAdmin: nUSer.IsAdmin,
|
||||
CreatedAt: nUSer.CreatedAt,
|
||||
UpdatedAt: nUSer.UpdatedAt,
|
||||
},
|
||||
}
|
||||
|
||||
// Return the new access token and the updated user object
|
||||
respondJSON(w, http.StatusOK, response)
|
||||
}
|
||||
|
||||
// Handler for hard deleting the current user. Requires the user's password as JSON input as a precaution.
|
||||
|
@ -24,10 +24,11 @@ WHERE id = $1 LIMIT 1;
|
||||
SELECT * FROM users
|
||||
WHERE username = $1 LIMIT 1;
|
||||
|
||||
-- name: UpdatePassword :exec
|
||||
-- name: UpdatePassword :one
|
||||
UPDATE users
|
||||
SET password_hash = $2, updated_at = NOW()
|
||||
WHERE id = $1;
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users
|
||||
|
Loading…
x
Reference in New Issue
Block a user