feat: change email, export my data, delete account (with data anonymization)
This commit is contained in:
1 parent
bb191c389a
commit
10a66cd979
123 files changed
+10789
-76
No files matched your search
@@ -0,0 +1,81 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
"RenewCMS/api/pkg/authtoken"
|
||||
"RenewCMS/api/pkg/claims"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
domain "RenewCMS/internal/domain/user"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DeleteAccountHandler struct {
|
||||
DeleteUseCase *useCases.DeleteOwnAccountUseCase
|
||||
IsProduction bool
|
||||
}
|
||||
|
||||
type DeleteAccountRequest struct {
|
||||
CurrentPassword string `json:"current_password" validate:"required"`
|
||||
Confirmation string `json:"confirmation" validate:"required,eq=DELETE"`
|
||||
}
|
||||
|
||||
func NewDeleteAccountHandler(deleteAccount *useCases.DeleteOwnAccountUseCase, isProduction bool) *DeleteAccountHandler {
|
||||
return &DeleteAccountHandler{DeleteUseCase: deleteAccount, IsProduction: isProduction}
|
||||
}
|
||||
|
||||
func (h *DeleteAccountHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
var request DeleteAccountRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate.Struct(request); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
userId, ok := claims.UserId(r)
|
||||
if !ok {
|
||||
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
command := useCases.DeleteOwnAccountCommand{UserID: userId, CurrentPassword: request.CurrentPassword}
|
||||
command.SessionID, command.SessionExpiresAt = sessionOf(r)
|
||||
if err := h.DeleteUseCase.Delete(r.Context(), command); err != nil {
|
||||
writeDeleteAccountError(w, err)
|
||||
return
|
||||
}
|
||||
http.SetCookie(w, authtoken.ExpiredCookie(h.IsProduction))
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func sessionOf(r *http.Request) (string, time.Time) {
|
||||
tokenClaims, err := authtoken.FromContext(r.Context())
|
||||
if err != nil {
|
||||
return "", time.Time{}
|
||||
}
|
||||
id, _ := tokenClaims["jti"].(string)
|
||||
expiry, _ := tokenClaims["exp"].(float64)
|
||||
return id, time.Unix(int64(expiry), 0)
|
||||
}
|
||||
|
||||
func writeDeleteAccountError(w http.ResponseWriter, err error) {
|
||||
var lastAdmin domain.LastAdminError
|
||||
switch {
|
||||
case errors.Is(err, domain.ErrUserNotFound):
|
||||
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
|
||||
case errors.Is(err, domain.ErrWrongPassword):
|
||||
http.Error(w, apperr.WrongPasswordErrorCode, http.StatusForbidden)
|
||||
case errors.As(err, &lastAdmin):
|
||||
w.Header().Set(apperr.LastRoleHeader, lastAdmin.Role)
|
||||
http.Error(w, apperr.LastAdminErrorCode, http.StatusConflict)
|
||||
case errors.Is(err, domain.ErrAccountNotDeletable):
|
||||
http.Error(w, apperr.AccountNotDeletableErrorCode, http.StatusConflict)
|
||||
default:
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user