292 lines
9.3 KiB
Go
292 lines
9.3 KiB
Go
package controllers
|
|
|
|
import (
|
|
"GoMembership/internal/config"
|
|
"GoMembership/internal/constants"
|
|
"GoMembership/internal/middlewares"
|
|
"GoMembership/internal/models"
|
|
"GoMembership/internal/services"
|
|
"GoMembership/internal/utils"
|
|
|
|
"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
|
|
}
|
|
|
|
type RegistrationData struct {
|
|
User models.User `json:"user"`
|
|
}
|
|
|
|
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)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode request data"})
|
|
return
|
|
}
|
|
tokenString, err := c.Cookie("jwt")
|
|
if err != nil {
|
|
logger.Error.Printf("No Auth token: %v\n", err)
|
|
c.JSON(http.StatusUnauthorized, gin.H{"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{"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{"error": "No user id provided"})
|
|
return
|
|
}
|
|
if user.ID != jwtUserID && userRole < constants.Roles.Editor {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "You are not authorized to update this user"})
|
|
return
|
|
}
|
|
if user.Membership.SubscriptionModel.Name == "" {
|
|
logger.Error.Printf("No subscription model provided: %v", user.Email)
|
|
c.JSON(http.StatusNotAcceptable, gin.H{"error": "No subscription model provided"})
|
|
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{"error": "Not a valid 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{"error": "User not found"})
|
|
case errors.ErrInvalidUserData:
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user data"})
|
|
default:
|
|
logger.Error.Printf("Failed to update user: %v", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server error"})
|
|
}
|
|
return
|
|
}
|
|
c.JSON(http.StatusAccepted, gin.H{"message": "User updated successfully", "user": updatedUser})
|
|
}
|
|
|
|
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{"error": "Missing or invalid user ID type"})
|
|
return
|
|
}
|
|
userID, ok := userIDInterface.(uint)
|
|
|
|
if !ok {
|
|
logger.Error.Printf("Error: user_id is not of type uint")
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user ID type"})
|
|
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{"error": "Error retrieving user."})
|
|
return
|
|
}
|
|
|
|
subscriptions, err := uc.MembershipService.GetSubscriptions(nil)
|
|
if err != nil {
|
|
logger.Error.Printf("Error retrieving subscriptions: %v", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving subscriptions."})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"user": user.Safe(),
|
|
"subscriptions": subscriptions,
|
|
})
|
|
}
|
|
|
|
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{"error": "Couldn't decode request data"})
|
|
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{"error": "Couldn't find user"})
|
|
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{"error": "couldn't calculate match"})
|
|
return
|
|
}
|
|
if !ok {
|
|
|
|
logger.Error.Printf("Wrong Password: %v %v", user.FirstName, user.LastName)
|
|
c.JSON(http.StatusNotAcceptable, gin.H{"error": "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{"error": "Failed to generate JWT token"})
|
|
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)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode userdata"})
|
|
return
|
|
}
|
|
if regData.User.Membership.SubscriptionModel.Name == "" {
|
|
logger.Error.Printf("No subscription model provided: %v", regData.User.Email)
|
|
c.JSON(http.StatusNotAcceptable, gin.H{"error": "No subscription model provided"})
|
|
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{"error": "Not a valid 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)
|
|
c.JSON(int(id), gin.H{"error": "Couldn't register User"})
|
|
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{"error": "Couldn't register User-consent"})
|
|
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})
|
|
|
|
}
|