package controllers import ( "GoMembership/internal/config" "GoMembership/internal/constants" "GoMembership/internal/middlewares" "GoMembership/internal/models" "GoMembership/internal/services" "GoMembership/internal/utils" "GoMembership/internal/validation" "fmt" "strings" "net/http" "github.com/gin-gonic/gin" "GoMembership/pkg/errors" "GoMembership/pkg/logger" ) type UserController struct { Service services.UserServiceInterface EmailService *services.EmailService ConsentService services.ConsentServiceInterface BankAccountService services.BankAccountServiceInterface MembershipService services.MembershipServiceInterface LicenceService services.LicenceInterface } type RegistrationData struct { User models.User `json:"user"` } func (uc *UserController) CurrentUserHandler(c *gin.Context) { requestUser, err := uc.ExtractUserFromContext(c) if err != nil { utils.RespondWithError(c, err, "Error extracting user from context in CurrentUserHandler", http.StatusBadRequest, "general", "server.error.internal_server_error") return } c.JSON(http.StatusOK, gin.H{ "user": requestUser.Safe(), }) } func (uc *UserController) GetAllUsers(c *gin.Context) { users, err := uc.Service.GetUsers(nil) if err != nil { utils.RespondWithError(c, err, "Error getting users in GetAllUsers", http.StatusInternalServerError, "user", "server.error.internal_server_error") return } // Create a slice to hold the safe user representations safeUsers := make([]map[string]interface{}, len(*users)) // Convert each user to its safe representation for i, user := range *users { safeUsers[i] = user.Safe() } c.JSON(http.StatusOK, gin.H{ "users": users, }) } func (uc *UserController) UpdateHandler(c *gin.Context) { // 1. Extract and validate the user ID from the route requestUser, err := uc.ExtractUserFromContext(c) if err != nil { utils.RespondWithError(c, err, "Error extracting user from context in UpdateHandler", http.StatusBadRequest, "general", "server.validation.no_auth_tokenw") return } var user models.User var updateData RegistrationData if err := c.ShouldBindJSON(&updateData); err != nil { utils.HandleValidationError(c, err) return } user = updateData.User if !utils.HasPrivilige(requestUser, constants.Priviliges.Update) && user.ID != requestUser.ID { utils.RespondWithError(c, errors.ErrNotAuthorized, "Not allowed to update user", http.StatusForbidden, "user", "server.error.unauthorized") return } updatedUser, err := uc.Service.UpdateUser(&user) if err != nil { utils.HandleUserUpdateError(c, err) return } logger.Info.Printf("User %d updated successfully by user %d", updatedUser.ID, requestUser.ID) 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) if err != nil { utils.RespondWithError(c, err, "Error extracting user from context in UpdateHandler", http.StatusBadRequest, "general", "server.validation.no_auth_tokenw") return } type deleteData = struct { ID uint `json:"id"` LastName string `json:"lastname"` } var deletedUser deleteData if err := c.ShouldBindJSON(&deletedUser); err != nil { utils.HandleValidationError(c, err) return } if !utils.HasPrivilige(requestUser, constants.Priviliges.Update) && deletedUser.ID != requestUser.ID { utils.RespondWithError(c, errors.ErrNotAuthorized, "Not allowed to delete user", http.StatusForbidden, "user", "server.error.unauthorized") return } if err := uc.Service.DeleteUser(deletedUser.LastName, deletedUser.ID); err != nil { utils.RespondWithError(c, err, "Error during user deletion", http.StatusInternalServerError, "user", "server.error.internal_server_error") return } } 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 { logger.Error.Printf("unable to get token from cookie: %#v", err) } middlewares.InvalidateSession(tokenString) c.SetCookie("jwt", "", -1, "/", "", true, true) c.JSON(http.StatusOK, gin.H{"message": "Logged out successfully"}) } func (uc *UserController) LoginHandler(c *gin.Context) { var input struct { Email string `json:"email"` Password string `json:"password"` } if err := c.ShouldBindJSON(&input); err != nil { utils.RespondWithError(c, err, "Error in LoginHandler", http.StatusBadRequest, "general", "server.validation.invalid_json") return } user, err := uc.Service.GetUserByEmail(input.Email) if err != nil { utils.RespondWithError(c, err, "Login Error; user not found", http.StatusNotFound, errors.Responses.Fields.Login, errors.Responses.Keys.UserNotFoundWrongPassword) return } ok, err := user.PasswordMatches(input.Password) if err != nil { utils.RespondWithError(c, err, "Login Error; password comparisson failed", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError) return } if !ok { utils.RespondWithError(c, fmt.Errorf("%v %v", user.FirstName, user.LastName), "Login Error; wrong password", http.StatusNotAcceptable, errors.Responses.Fields.Login, errors.Responses.Keys.UserNotFoundWrongPassword) return } logger.Error.Printf("jwtsecret: %v", config.Auth.JWTSecret) token, err := middlewares.GenerateToken(config.Auth.JWTSecret, user, "") if err != nil { utils.RespondWithError(c, err, "Error generating token in LoginHandler", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.JwtGenerationFailed) return } utils.SetCookie(c, token) c.JSON(http.StatusOK, gin.H{ "message": "Login successful", }) } func (uc *UserController) RegisterUser(c *gin.Context) { var regData RegistrationData if err := c.ShouldBindJSON(®Data); err != nil { utils.HandleValidationError(c, err) return } logger.Info.Printf("Registering user %v", regData.User.Email) selectedModel, err := uc.MembershipService.GetModelByName(®Data.User.Membership.SubscriptionModel.Name) if err != nil { utils.RespondWithError(c, err, "Error in Registeruser, couldn't get selected model", http.StatusNotFound, "subscription_model", "server.validation.subscription_model_not_found") 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, "parent_membership_id", "server.validation.parent_membership_id_not_found") return } } regData.User.RoleID = constants.Roles.Member // Register User id, token, err := uc.Service.RegisterUser(®Data.User) if err != nil { logger.Error.Printf("Couldn't register User(%v): %v", regData.User.Email, err) if strings.Contains(err.Error(), "UNIQUE constraint failed: users.email") { utils.RespondWithError(c, err, "Error in RegisterUser, couldn't register user", http.StatusConflict, "email", "server.validation.email_already_exists") } else { utils.RespondWithError(c, err, "Error in RegisterUser, couldn't register user", http.StatusConflict, "general", "server.error.internal_server_error") } return } regData.User.ID = id // Register Consents var consents = [2]models.Consent{ { FirstName: regData.User.FirstName, LastName: regData.User.LastName, Email: regData.User.Email, ConsentType: "TermsOfService", }, { FirstName: regData.User.FirstName, LastName: regData.User.LastName, Email: regData.User.Email, ConsentType: "Privacy", }, } for _, consent := range consents { _, err = uc.ConsentService.RegisterConsent(&consent) if err != nil { utils.RespondWithError(c, err, "Error in RegisterUser, couldn't register consent", http.StatusInternalServerError, "general", "server.error.internal_server_error") return } } // Send notifications if err := uc.EmailService.SendVerificationEmail(®Data.User, &token); err != nil { logger.Error.Printf("Failed to send email verification email to user(%v): %v", regData.User.Email, err) // Proceed without returning error since user registration is successful // TODO Notify Admin } // Notify admin of new user registration if err := uc.EmailService.SendRegistrationNotification(®Data.User); err != nil { logger.Error.Printf("Failed to notify admin of new user(%v) registration: %v", regData.User.Email, err) // Proceed without returning error since user registration is successful // TODO Notify Admin } c.JSON(http.StatusCreated, gin.H{ "message": "Registration successuful", "id": regData.User.ID, }) } func (uc *UserController) VerifyMailHandler(c *gin.Context) { token := c.Query("token") if token == "" { logger.Error.Println("Missing token to verify mail") c.HTML(http.StatusBadRequest, "verification_error.html", gin.H{"ErrorMessage": "Missing token"}) return } user, err := uc.Service.VerifyUser(&token) if err != nil { logger.Error.Printf("Cannot verify user: %v", err) c.HTML(http.StatusUnauthorized, "verification_error.html", gin.H{"ErrorMessage": "Emailadresse wurde schon bestÃĪtigt. Sollte dies nicht der Fall sein, wende Dich bitte an info@carsharing-hasloh.de."}) return } logger.Info.Printf("VerificationMailHandler User: %#v", user.Email) uc.EmailService.SendWelcomeEmail(user) c.HTML(http.StatusOK, "verification_success.html", gin.H{"FirstName": user.FirstName}) }