adapted new user model.

This commit is contained in:
Alex
2025-03-11 20:52:39 +01:00
parent e60aaa1d69
commit 9d2b33f832
3 changed files with 108 additions and 114 deletions

View File

@@ -9,11 +9,14 @@ import (
"GoMembership/internal/utils"
"GoMembership/internal/validation"
"fmt"
"strconv"
"strings"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
"GoMembership/pkg/errors"
"GoMembership/pkg/logger"
@@ -25,7 +28,7 @@ type UserController struct {
ConsentService services.ConsentServiceInterface
BankAccountService services.BankAccountServiceInterface
MembershipService services.MembershipServiceInterface
LicenceService services.LicenceInterface
LicenceService services.LicenceServiceInterface
}
type RegistrationData struct {
@@ -33,7 +36,7 @@ type RegistrationData struct {
}
func (uc *UserController) CurrentUserHandler(c *gin.Context) {
requestUser, err := uc.ExtractUserFromContext(c)
requestUser, err := uc.Service.FromContext(c)
if err != nil {
utils.RespondWithError(c, err, "Error extracting user from context in CurrentUserHandler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
return
@@ -46,19 +49,20 @@ func (uc *UserController) CurrentUserHandler(c *gin.Context) {
func (uc *UserController) GetAllUsers(c *gin.Context) {
requestUser, err := uc.ExtractUserFromContext(c)
requestUser, err := uc.Service.FromContext(c)
if err != nil {
utils.RespondWithError(c, err, "Error extracting user from context in UpdateHandler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
return
}
if !utils.HasPrivilige(requestUser, constants.Priviliges.View) {
if !requestUser.HasPrivilege(constants.Priviliges.View) {
utils.RespondWithError(c, errors.ErrNotAuthorized, fmt.Sprintf("Not allowed to handle all users. RoleID(%v)<Privilige(%v)", requestUser.RoleID, constants.Priviliges.View), http.StatusForbidden, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
return
}
users, err := uc.Service.GetUsers(nil)
if err != nil {
utils.RespondWithError(c, err, "Error getting users in GetAllUsers", http.StatusInternalServerError, errors.Responses.Fields.User, errors.Responses.Keys.InternalServerError)
utils.RespondWithError(c, err, "Error getting all users", http.StatusInternalServerError, errors.Responses.Fields.User, errors.Responses.Keys.InternalServerError)
return
}
@@ -69,6 +73,7 @@ func (uc *UserController) GetAllUsers(c *gin.Context) {
for i, user := range *users {
safeUsers[i] = user.Safe()
}
c.JSON(http.StatusOK, gin.H{
"users": users,
})
@@ -76,7 +81,7 @@ func (uc *UserController) GetAllUsers(c *gin.Context) {
func (uc *UserController) UpdateHandler(c *gin.Context) {
// 1. Extract and validate the user ID from the route
requestUser, err := uc.ExtractUserFromContext(c)
requestUser, err := uc.Service.FromContext(c)
if err != nil {
utils.RespondWithError(c, err, "Error extracting user from context in UpdateHandler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
return
@@ -89,28 +94,20 @@ func (uc *UserController) UpdateHandler(c *gin.Context) {
}
user := updateData.User
if !utils.HasPrivilige(requestUser, constants.Priviliges.Update) && user.ID != requestUser.ID {
if !requestUser.HasPrivilege(constants.Priviliges.Update) && user.ID != requestUser.ID {
utils.RespondWithError(c, errors.ErrNotAuthorized, "Not allowed to update user", http.StatusForbidden, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
return
}
existingUser, err := uc.Service.GetUserByID(user.ID)
if err != nil {
utils.RespondWithError(c, err, "Error finding an existing user", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound)
return
}
user.MembershipID = existingUser.MembershipID
user.Membership.ID = existingUser.Membership.ID
if existingUser.Licence != nil {
user.Licence.ID = existingUser.Licence.ID
}
user.LicenceID = existingUser.LicenceID
user.BankAccount.ID = existingUser.BankAccount.ID
user.BankAccountID = existingUser.BankAccountID
if requestUser.RoleID <= constants.Priviliges.View {
if requestUser.IsMember() {
existingUser, err := uc.Service.FromID(&user.ID)
if err != nil {
utils.RespondWithError(c, err, "Error finding an existing user", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound)
return
}
// deleting existing Users Password to prevent it from being recognized as changed in any case. (Incoming Password is empty if not changed)
existingUser.Password = ""
if err := utils.FilterAllowedStructFields(&user, existingUser, constants.MemberUpdateFields, ""); err != nil {
if err := validation.FilterAllowedStructFields(&user, existingUser, constants.MemberUpdateFields, ""); err != nil {
if err.Error() == "Not authorized" {
utils.RespondWithError(c, errors.ErrNotAuthorized, "Trying to update unauthorized fields", http.StatusUnauthorized, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
} else {
@@ -120,20 +117,20 @@ func (uc *UserController) UpdateHandler(c *gin.Context) {
}
}
updatedUser, err := uc.Service.UpdateUser(&user)
updatedUser, err := uc.Service.Update(&user)
if err != nil {
utils.HandleUserUpdateError(c, err)
return
}
logger.Info.Printf("User %d updated successfully by user %d", updatedUser.ID, requestUser.ID)
logger.Info.Printf("User %v updated successfully by user %v", updatedUser.Email, requestUser.Email)
c.JSON(http.StatusAccepted, gin.H{"message": "User updated successfully", "user": updatedUser.Safe()})
}
func (uc *UserController) DeleteUser(c *gin.Context) {
requestUser, err := uc.ExtractUserFromContext(c)
requestUser, err := uc.Service.FromContext(c)
if err != nil {
utils.RespondWithError(c, err, "Error extracting user from context in DeleteUser", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
return
@@ -152,13 +149,13 @@ func (uc *UserController) DeleteUser(c *gin.Context) {
return
}
if !utils.HasPrivilige(requestUser, constants.Priviliges.Delete) && data.User.ID != requestUser.ID {
if !requestUser.HasPrivilege(constants.Priviliges.Delete) && data.User.ID != requestUser.ID {
utils.RespondWithError(c, errors.ErrNotAuthorized, "Not allowed to delete user", http.StatusForbidden, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
return
}
logger.Error.Printf("Deleting user: %v", data.User)
if err := uc.Service.DeleteUser(data.User.LastName, data.User.ID); err != nil {
if err := uc.Service.Delete(&data.User.ID); err != nil {
utils.HandleDeleteUserError(c, err)
return
}
@@ -166,24 +163,6 @@ func (uc *UserController) DeleteUser(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "User deleted successfully"})
}
func (uc *UserController) ExtractUserFromContext(c *gin.Context) (*models.User, error) {
tokenString, err := c.Cookie("jwt")
if err != nil {
return nil, err
}
_, claims, err := middlewares.ExtractContentFrom(tokenString)
if err != nil {
return nil, err
}
jwtUserID := uint((*claims)["user_id"].(float64))
user, err := uc.Service.GetUserByID(jwtUserID)
if err != nil {
return nil, err
}
return user, nil
}
func (uc *UserController) LogoutHandler(c *gin.Context) {
tokenString, err := c.Cookie("jwt")
if err != nil {
@@ -207,7 +186,7 @@ func (uc *UserController) LoginHandler(c *gin.Context) {
return
}
user, err := uc.Service.GetUserByEmail(input.Email)
user, err := uc.Service.FromEmail(&input.Email)
if err != nil {
utils.RespondWithError(c, err, "Login Error; user not found", http.StatusNotFound,
errors.Responses.Fields.Login,
@@ -215,9 +194,9 @@ func (uc *UserController) LoginHandler(c *gin.Context) {
return
}
if user.Status <= constants.DisabledStatus {
utils.RespondWithError(c, fmt.Errorf("User banned from login %v %v", user.FirstName, user.LastName),
"Login Error; user is disabled",
if !user.IsVerified() {
utils.RespondWithError(c, fmt.Errorf("User banned from login or not verified %v %v", user.FirstName, user.LastName),
"Login Error; user is disabled or not verified",
http.StatusNotAcceptable,
errors.Responses.Fields.Login,
errors.Responses.Keys.UserDisabled)
@@ -238,8 +217,10 @@ func (uc *UserController) LoginHandler(c *gin.Context) {
return
}
logger.Error.Printf("jwtsecret: %v", config.Auth.JWTSecret)
token, err := middlewares.GenerateToken(config.Auth.JWTSecret, user, "")
// "user_id": user.ID,
// "role_id": user.RoleID,
claims := map[string]interface{}{"user_id": user.ID, "role_id": user.RoleID}
token, err := middlewares.GenerateToken(&config.Auth.JWTSecret, claims, "")
if err != nil {
utils.RespondWithError(c, err, "Error generating token in LoginHandler", http.StatusInternalServerError, errors.Responses.Fields.Login, errors.Responses.Keys.JwtGenerationFailed)
return
@@ -256,7 +237,6 @@ func (uc *UserController) LoginHandler(c *gin.Context) {
func (uc *UserController) RegisterUser(c *gin.Context) {
var regData RegistrationData
logger.Error.Printf("registering user...")
if err := c.ShouldBindJSON(&regData); err != nil {
utils.HandleValidationError(c, err)
return
@@ -269,11 +249,13 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
return
}
regData.User.Membership.SubscriptionModel = *selectedModel
if selectedModel.RequiredMembershipField != "" {
if err := validation.CheckParentMembershipID(regData.User.Membership); err != nil {
utils.RespondWithError(c, err, "Error in RegisterUser, couldn't check parent membership id", http.StatusBadRequest, errors.Responses.Fields.ParentMemberShipID, errors.Responses.Keys.NotFound)
return
}
// Get Gin's binding validator engine with all registered validators
validate := binding.Validator.Engine().(*validator.Validate)
// Validate the populated user struct
if err := validate.Struct(regData.User); err != nil {
utils.HandleValidationError(c, err)
return
}
if regData.User.Membership.SubscriptionModel.Name == constants.SupporterSubscriptionModelName {
regData.User.RoleID = constants.Roles.Supporter
@@ -282,9 +264,9 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
}
// Register User
id, token, err := uc.Service.RegisterUser(&regData.User)
id, token, err := uc.Service.Register(&regData.User)
if err != nil {
if strings.Contains(err.Error(), "UNIQUE constraint failed: users.email") {
if strings.Contains(err.Error(), "UNIQUE constraint failed:") {
utils.RespondWithError(c, err, "Error in RegisterUser, couldn't register user", http.StatusConflict, errors.Responses.Fields.Email, errors.Responses.Keys.Duplicate)
} else {
utils.RespondWithError(c, err, "Error in RegisterUser, couldn't register user", http.StatusConflict, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError)
@@ -294,7 +276,7 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
regData.User.ID = id
// if this is a supporter don't send mails and he never did give any consent. So stop here
if regData.User.RoleID == constants.Roles.Supporter {
if regData.User.IsSupporter() {
c.JSON(http.StatusCreated, gin.H{
"message": "Supporter Registration successuful",
@@ -318,6 +300,7 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
ConsentType: "Privacy",
},
}
for _, consent := range consents {
_, err = uc.ConsentService.RegisterConsent(&consent)
if err != nil {
@@ -326,6 +309,7 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
}
}
logger.Error.Printf("Sending Verification mail to user with id: %#v", id)
// Send notifications
if err := uc.EmailService.SendVerificationEmail(&regData.User, &token); err != nil {
utils.RespondWithError(c, err, "Error in RegisterUser, couldn't send verification email", http.StatusInternalServerError, errors.Responses.Fields.Email, errors.Responses.Keys.UndeliveredVerificationMail)
@@ -351,26 +335,35 @@ func (uc *UserController) VerifyMailHandler(c *gin.Context) {
c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Missing token"})
return
}
verification, err := uc.Service.VerifyUser(&token, &constants.VerificationTypes.Email)
userIDint, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Couldn't verify user"})
logger.Error.Println("Missing user ID to verify mail")
c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Missing user"})
return
}
user, err := uc.Service.GetUserByID(verification.UserID)
userID := uint(userIDint)
user, err := uc.Service.FromID(&userID)
if err != nil {
c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Internal server error, couldn't verify user"})
logger.Error.Printf("Couldn't find user in verifyMailHandler: %#v", err)
c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Couldn't find user"})
return
}
if !user.Verify(token, constants.VerificationTypes.Email) {
logger.Error.Printf("Couldn't find user verification in verifyMailHandler: %v", err)
c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Couldn't find user verification request"})
return
}
user.Status = constants.VerifiedStatus
user.Verification = *verification
user.ID = verification.UserID
user.Password = ""
uc.Service.UpdateUser(user)
logger.Info.Printf("Verified User: %#v", user.Email)
updatedUser, err := uc.Service.Update(user)
if err != nil {
logger.Error.Printf("Failed to update user(%v) after verification: %v", user.Email, err)
c.HTML(http.StatusInternalServerError, "verification_error.html", gin.H{"ErrorMessage": "Internal server error, couldn't verify user"})
return
}
logger.Info.Printf("Verified User: %#v", updatedUser.Email)
uc.EmailService.SendWelcomeEmail(user)
c.HTML(http.StatusOK, "verification_success.html", gin.H{"FirstName": user.FirstName})