package controllers import ( "GoMembership/internal/config" "GoMembership/internal/constants" "GoMembership/internal/middlewares" "GoMembership/internal/models" "GoMembership/internal/services" "GoMembership/internal/utils" "strings" "net/http" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "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) { userIDInterface, ok := c.Get("user_id") if !ok || userIDInterface == nil { logger.Error.Printf("Error getting user_id from header") c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.validation.no_user_id_provided", }}}) return } userID, ok := userIDInterface.(uint) if !ok { logger.Error.Printf("Error: user_id is not of type uint") c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "user", "key": "server.error.internal_server_error", }}}) return } user, err := uc.Service.GetUserByID(uint(userID)) if err != nil { logger.Error.Printf("Error retrieving valid user: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.internal_server_error", }}}) return } c.JSON(http.StatusOK, gin.H{ "user": user.Safe(), }) } func (uc *UserController) GetAllUsers(c *gin.Context) { users, err := uc.Service.GetUsers(nil) if err != nil { logger.Error.Printf("Error retrieving users: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.internal_server_error", }}}) return } c.JSON(http.StatusOK, gin.H{ "users": users, }) } func (uc *UserController) UpdateHandler(c *gin.Context) { var user models.User if err := c.ShouldBindJSON(&user); err != nil { logger.Error.Printf("Couldn't decode input: %v", err) var validationErrors []gin.H if ve, ok := err.(validator.ValidationErrors); ok { for _, e := range ve { validationErrors = append(validationErrors, gin.H{ "field": e.Field(), "key": "server.validation." + e.Tag(), }) } } else { validationErrors = append(validationErrors, gin.H{ "field": "general", "key": "server.error.invalid_json", }) } logger.Error.Printf("ValidationErrors: %#v", validationErrors) c.JSON(http.StatusBadRequest, gin.H{"errors": validationErrors}) c.Abort() return } logger.Error.Print("Continuing...") tokenString, err := c.Cookie("jwt") if err != nil { logger.Error.Printf("No Auth token: %v\n", err) c.JSON(http.StatusUnauthorized, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.no_auth_token", }}}) c.Abort() return } _, claims, err := middlewares.ExtractContentFrom(tokenString) if err != nil { logger.Error.Printf("Error retrieving token and claims from JWT") c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.jwt_parsing_error", }}}) return } jwtUserID := uint((*claims)["user_id"].(float64)) userRole := int8((*claims)["role_id"].(float64)) if user.ID == 0 { logger.Error.Printf("No User.ID in request from user with id: %v, aborting", jwtUserID) c.JSON(http.StatusBadRequest, gin.H{"errors": []gin.H{{ "field": "id", "key": "server.validation.no_user_id_provided", }}}) return } if user.ID != jwtUserID && userRole < constants.Roles.Editor { c.JSON(http.StatusForbidden, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.unauthorized_update", }}}) return } selectedModel, err := uc.MembershipService.GetModelByName(&user.Membership.SubscriptionModel.Name) if err != nil { logger.Error.Printf("%v:No subscription model found: %#v", user.Email, err) c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ "field": "subscription_model", "key": "server.validation.invalid_subscription_model", }}}) return } user.Membership.SubscriptionModel = *selectedModel // TODO: If it's not an admin, prevent changes to critical fields // if userRole != constants.Roles.Admin { // existingUser, err := uc.Service.GetUserByID(jwtUserID) // if err != nil { // c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving user data"}) // return // } // user.Email = existingUser.Email // user.RoleID = existingUser.RoleID // } updatedUser, err := uc.Service.UpdateUser(&user, userRole) if err != nil { switch err { case errors.ErrUserNotFound: c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ "field": user.FirstName + " " + user.LastName, "key": "server.validation.user_not_found", }}}) case errors.ErrInvalidUserData: c.JSON(http.StatusBadRequest, gin.H{"errors": []gin.H{{ "field": "user", "key": "server.validation.invalid_user_data", }}}) default: logger.Error.Printf("Failed to update user: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.internal_server_error", }}}) return } } c.JSON(http.StatusAccepted, gin.H{"message": "User updated successfully", "user": updatedUser}) } 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 { logger.Error.Printf("Couldn't decode input: %v", err.Error()) c.JSON(http.StatusBadRequest, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.invalid_json", }}}) return } user, err := uc.Service.GetUserByEmail(input.Email) if err != nil { logger.Error.Printf("Error during user(%v) retrieval: %v\n", input.Email, err) c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ "field": "login", "key": "server.validation.user_not_found_or_wrong_password", }}}) return } ok, err := user.PasswordMatches(input.Password) if err != nil { logger.Error.Printf("Error during Password comparison: %v", err.Error()) c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.internal_server_error", }}}) return } if !ok { logger.Error.Printf("Wrong Password: %v %v", user.FirstName, user.LastName) c.JSON(http.StatusNotAcceptable, gin.H{"errors": []gin.H{{ "field": "login", "key": "server.validation.user_not_found_or_wrong_password", }}}) return } logger.Error.Printf("jwtsevret: %v", config.Auth.JWTSecret) token, err := middlewares.GenerateToken(config.Auth.JWTSecret, user, "") if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "server.error.jwt_generation_failed", }}}) 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 { logger.Error.Printf("Couldn't decode Userdata: %v", err) var validationErrors []gin.H if ve, ok := err.(validator.ValidationErrors); ok { for _, e := range ve { validationErrors = append(validationErrors, gin.H{ "field": e.Field(), "key": "server.validation." + e.Tag(), }) } } else { validationErrors = append(validationErrors, gin.H{ "field": "general", "key": "server.error.invalid_json", }) } c.JSON(http.StatusBadRequest, gin.H{"error": validationErrors}) return } selectedModel, err := uc.MembershipService.GetModelByName(®Data.User.Membership.SubscriptionModel.Name) if err != nil { logger.Error.Printf("%v:No subscription model found: %#v", regData.User.Email, err) c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ "field": "subscription_model", "key": "server.validation.invalid_subscription_model", }}}) return } regData.User.Membership.SubscriptionModel = *selectedModel 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") { c.JSON(http.StatusConflict, gin.H{"errors": []gin.H{{ "field": "email", "key": "server.validation.email_already_registered", }}}) } else { logger.Error.Printf("Failed to register user: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "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 { logger.Error.Printf("%v, Couldn't register consent: %v", regData.User.Email, err) c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ "field": "general", "key": "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 } // 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 } 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}) }