switched to gin-gonic

This commit is contained in:
$(pass /github/name)
2024-07-11 12:28:39 +02:00
parent 20ed629e92
commit de88a603d5
11 changed files with 330 additions and 169 deletions

View File

@@ -1,16 +1,14 @@
package controllers
import (
"encoding/json"
"GoMembership/internal/config"
"GoMembership/internal/models"
"GoMembership/internal/services"
// "github.com/gorilla/mux"
"net/http"
// "strconv"
"GoMembership/internal/utils"
"github.com/gin-gonic/gin"
"GoMembership/pkg/logger"
)
@@ -26,24 +24,23 @@ func NewMembershipController(service services.MembershipService) *MembershipCont
return &MembershipController{service}
}
func (uc *MembershipController) RegisterSubscription(w http.ResponseWriter, r *http.Request) {
rh := utils.NewResponseHandler(w)
func (uc *MembershipController) RegisterSubscription(c *gin.Context) {
var regData MembershipData
if err := json.NewDecoder(r.Body).Decode(&regData); err != nil {
logger.Error.Printf("Couldn't decode SubscriptionModel: %v", err)
rh.RespondWithError(http.StatusBadRequest, "Couldn't decode Membershipmodel")
return
if err := c.ShouldBindJSON(&regData); err != nil {
logger.Error.Printf("Couln't decode subscription data: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode subscription data"})
}
logger.Info.Printf("Using API key: %v", config.LoadConfig().Auth.APIKEY)
if regData.APIKey == "" {
logger.Error.Println("API Key is missing")
rh.RespondWithError(http.StatusBadRequest, "API Key is required")
c.JSON(http.StatusBadRequest, "API Key is missing")
return
}
if regData.APIKey != config.LoadConfig().Auth.APIKEY {
logger.Error.Printf("API Key not valid: %v", regData.APIKey)
rh.RespondWithError(http.StatusExpectationFailed, "API Key not valid")
c.JSON(http.StatusExpectationFailed, "API Key is missing")
return
}
logger.Info.Printf("registering subscription: %+v", regData)
@@ -52,7 +49,7 @@ func (uc *MembershipController) RegisterSubscription(w http.ResponseWriter, r *h
id, err := uc.service.RegisterSubscription(&regData.Model)
if err != nil {
logger.Error.Printf("Couldn't register Membershipmodel: %v", err)
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register Membershipmodel")
c.JSON(http.StatusInternalServerError, "Couldn't register Membershipmodel")
return
}
regData.Model.ID = id

View File

@@ -1,15 +1,12 @@
package controllers
import (
"encoding/json"
"GoMembership/internal/models"
"GoMembership/internal/services"
// "github.com/gorilla/mux"
"github.com/gin-gonic/gin"
"net/http"
// "strconv"
"GoMembership/internal/utils"
"GoMembership/pkg/logger"
)
@@ -31,15 +28,13 @@ func NewUserController(service services.UserService, emailService *services.Emai
return &UserController{service, *emailService, consentService, bankAccountService, membershipService}
}
func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
rh := utils.NewResponseHandler(w)
func (uc *UserController) RegisterUser(c *gin.Context) {
var regData RegistrationData
if err := json.NewDecoder(r.Body).Decode(&regData); err != nil {
// http.Error(w, err.Error(), http.StatusBadRequest)
if err := c.ShouldBindJSON(&regData); err != nil {
logger.Error.Printf("Couldn't decode Userdata: %v", err)
rh.RespondWithError(http.StatusBadRequest, "Couldn't decode userdata")
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode userdata"})
return
}
logger.Info.Printf("registering user: %v", regData.User)
@@ -47,9 +42,8 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
// Register User
id, token, err := uc.service.RegisterUser(&regData.User)
if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
logger.Error.Printf("Couldn't register User: %v", err)
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User")
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User"})
return
}
regData.User.ID = id
@@ -58,7 +52,7 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
_, err = uc.bankAccountService.RegisterBankAccount(&regData.BankAccount)
if err != nil {
logger.Error.Printf("Couldn't register bank account: %v", err)
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User-BankAccount")
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-BankAccount"})
return
}
@@ -81,7 +75,7 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
_, err = uc.consentService.RegisterConsent(&consent)
if err != nil {
logger.Error.Printf("Couldn't register consent: %v", err)
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User-consent")
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-consent"})
return
}
}
@@ -90,48 +84,53 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
_, err = uc.membershipService.RegisterMembership(&regData.Membership)
if err != nil {
logger.Error.Printf("Couldn't register membership: %v", err)
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User-membership")
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-membership"})
return
}
// Send notifications
if err := uc.emailService.SendVerificationEmail(&regData.User, &token); err != nil {
logger.Error.Printf("Failed to send email verification email to user: %v", err)
// rh.RespondWithError(http.StatusServiceUnavailable, "User creation succeeded, but failed to send welcome email to user")
// Proceed without returning error since user registration is successful
}
// Notify admin of new user registration
if err := uc.emailService.NotifyAdminOfNewUser(&regData.User); err != nil {
logger.Error.Printf("Failed to notify admin of new user registration: %v", err)
// rh.RespondWithError(http.StatusServiceUnavailable, "User creation succeeded, but failed to notify admin of new user registration")
// Proceed without returning error since user registration is successful
}
rh.RespondWithJSON(http.StatusCreated, map[string]interface{}{
c.JSON(http.StatusCreated, gin.H{
"status": "success",
"id": regData.User.ID,
})
}
func (uc *UserController) VerifyMailHandler(w http.ResponseWriter, r *http.Request) {
rh := utils.NewResponseHandler(w)
token := r.URL.Query().Get("token")
func (uc *UserController) VerifyMailHandler(c *gin.Context) {
token := c.Query("token")
if token == "" {
logger.Error.Println("Missing token to verify mail")
rh.RespondWithError(http.StatusNoContent, "Missing token")
c.JSON(http.StatusNoContent, gin.H{"error": "Missing token"})
return
}
user, err := uc.service.VerifyUser(&token)
if err != nil {
logger.Error.Printf("Cannot verify user: %v", err)
rh.RespondWithError(http.StatusUnauthorized, "Cannot verify user")
c.JSON(http.StatusUnauthorized, gin.H{"error": "Cannot verify user"})
return
}
membership, err := uc.membershipService.FindMembershipByUserID(user.ID)
if err != nil {
logger.Error.Printf("Cannot get membership of user %v: %v", user.ID, err)
rh.RespondWithError(http.StatusInternalServerError, "Cannot get Membership of user")
c.JSON(http.StatusInternalServerError, gin.H{"error": "Cannot get Membership of user"})
return
}
uc.emailService.SendWelcomeEmail(user, membership)
c.Status(http.StatusOK)
}
/* func (uc *UserController) LoginUser(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,17 +1,33 @@
package middlewares
import (
"GoMembership/pkg/logger"
"net/http"
"time"
"GoMembership/pkg/logger"
"github.com/gin-gonic/gin"
)
// LoggerMiddleware logs each incoming HTTP request
func LoggerMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
logger.Info.Printf("%s %s %s", r.Method, r.RequestURI, time.Since(start))
next.ServeHTTP(w, r)
})
// LoggerMiddleware logs the incoming requests.
func LoggerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
startTime := time.Now()
// Process the request
c.Next()
// Calculate the latency
latency := time.Since(startTime)
// Get the status code
statusCode := c.Writer.Status()
// Log the details
logger.Info.Printf("| %3d | %13v | %15s | %-7s %#v\n",
statusCode,
latency,
c.ClientIP(),
c.Request.Method,
c.Request.URL.Path,
)
}
}

View File

@@ -1,23 +1,27 @@
package repositories
import (
"GoMembership/internal/constants"
"time"
"GoMembership/internal/constants"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"GoMembership/internal/models"
"GoMembership/pkg/errors"
"gorm.io/gorm/clause"
"GoMembership/pkg/logger"
)
type UserRepository interface {
CreateUser(user *models.User) (int64, error)
UpdateUser(userID int64, user *models.User) error
FindUserByID(id int64) (*models.User, error)
FindUserByEmail(email string) (*models.User, error)
SetVerificationToken(user *models.User, token *string) (int64, error)
IsVerified(userID *int64) (bool, error)
VerifyUserOfToken(token *string) (int64, error)
VerifyUserOfToken(token *string) (*models.User, error)
}
type userRepository struct {
@@ -36,11 +40,12 @@ func (repo *userRepository) CreateUser(user *models.User) (int64, error) {
return user.ID, nil
}
func (repo *userRepository) UpdateUser(userID int64, updates map[string]interface{}) error {
if len(updates) == 0 {
func (repo *userRepository) UpdateUser(userID int64, user *models.User) error {
logger.Info.Printf("Updating User: %#v\n", user)
if user == nil {
return errors.ErrNoData
}
result := repo.db.Session(&gorm.Session{FullSaveAssociations: true}).Model(&models.User{}).Where("id = ?", userID).Updates(&updates)
result := repo.db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
if result.Error != nil {
return result.Error
}
@@ -54,7 +59,7 @@ func (repo *userRepository) UpdateUser(userID int64, updates map[string]interfac
func (repo *userRepository) FindUserByID(id int64) (*models.User, error) {
var user models.User
result := repo.db.First(&user, id)
result := repo.db.Preload("Consents").Preload("BankAccount").Preload("Verification").Preload("Membership").First(&user, id)
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return nil, gorm.ErrRecordNotFound
@@ -88,38 +93,40 @@ func (repo *userRepository) IsVerified(userID *int64) (bool, error) {
return user.Status != constants.UnverifiedStatus, nil
}
func (repo *userRepository) VerifyUserOfToken(token *string) (int64, error) {
func (repo *userRepository) VerifyUserOfToken(token *string) (*models.User, error) {
var emailVerification models.Verification
result := repo.db.Where("verification_token = ?", token).First(&emailVerification)
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return 0, gorm.ErrRecordNotFound
return nil, gorm.ErrRecordNotFound
}
return 0, result.Error
return nil, result.Error
}
// Check if the user is already verified
verified, err := repo.IsVerified(&emailVerification.UserID)
if err != nil {
return 0, err
return nil, err
}
user, err := repo.FindUserByID(emailVerification.UserID)
if err != nil {
return nil, err
}
if verified {
return emailVerification.UserID, gorm.ErrRecordNotFound
return user, errors.ErrAlreadyVerified
}
// Update user status to active
t := time.Now()
emailVerification.EmailVerifiedAt = &t
update := map[string]interface{}{
"status": constants.VerifiedStatus,
"verifications": emailVerification,
}
err = repo.UpdateUser(emailVerification.UserID, update)
user.Status = constants.VerifiedStatus
user.Verification = emailVerification
err = repo.UpdateUser(emailVerification.UserID, user)
if err != nil {
return 0, err
return nil, err
}
return emailVerification.UserID, nil
return user, nil
}
func (repo *userRepository) SetVerificationToken(user *models.User, token *string) (int64, error) {

View File

@@ -2,18 +2,14 @@ package routes
import (
"GoMembership/internal/controllers"
// "GoMembership/internal/middlewares"
"GoMembership/pkg/logger"
// "net/http"
"github.com/gorilla/mux"
"github.com/gin-gonic/gin"
)
func RegisterRoutes(router *mux.Router, userController *controllers.UserController, membershipController *controllers.MembershipController) {
logger.Info.Println("Registering backend/api/register route")
router.HandleFunc("/backend/api/verify", userController.VerifyMailHandler).Methods("GET")
router.HandleFunc("/backend/api/register", userController.RegisterUser).Methods("POST")
router.HandleFunc("/backend/api/register/subscription", membershipController.RegisterSubscription).Methods("POST")
func RegisterRoutes(router *gin.Engine, userController *controllers.UserController, membershipController *controllers.MembershipController) {
router.GET("/backend/verify", userController.VerifyMailHandler)
router.POST("/backend/api/register", userController.RegisterUser)
router.POST("/backend/api/register/subscription", membershipController.RegisterSubscription)
// router.HandleFunc("/login", userController.LoginUser).Methods("POST")
}

View File

@@ -6,13 +6,13 @@ import (
"GoMembership/internal/config"
"GoMembership/internal/controllers"
"GoMembership/internal/database"
"GoMembership/internal/middlewares"
// "GoMembership/internal/middlewares"
"GoMembership/internal/repositories"
"GoMembership/internal/routes"
"GoMembership/internal/services"
"GoMembership/pkg/logger"
"github.com/gorilla/mux"
"github.com/gin-gonic/gin"
)
func Run() {
@@ -35,12 +35,11 @@ func Run() {
userService := services.NewUserService(userRepo)
userController := controllers.NewUserController(userService, emailService, consentService, bankAccountService, membershipService)
membershipController := controllers.NewMembershipController(membershipService)
router := mux.NewRouter()
// router.Handle("/csrf-token", middlewares.GenerateCSRFTokenHandler()).Methods("GET")
// Apply CSRF middleware
// router.Use(middlewares.CSRFMiddleware)
router.Use(middlewares.LoggerMiddleware)
router := gin.Default()
// gin.SetMode(gin.ReleaseMode)
router.Use(gin.Logger())
// router.Use(middlewares.LoggerMiddleware())
routes.RegisterRoutes(router, userController, membershipController)
// create subrouter for teh authenticated area /account

View File

@@ -39,6 +39,7 @@ func (service *userService) RegisterUser(user *models.User) (int64, string, erro
return -1, err
}
user.Password = string(hashedPassword) */
// TODO: Validate Data
user.Status = constants.UnverifiedStatus
user.CreatedAt = time.Now()
user.UpdatedAt = time.Now()
@@ -53,7 +54,7 @@ func (service *userService) RegisterUser(user *models.User) (int64, string, erro
return -1, "", err
}
logger.Info.Printf("user: %+v", user)
logger.Info.Printf("TOKEN: %v", token)
_, err = service.repo.SetVerificationToken(user, &token)
if err != nil {
return -1, "", err
@@ -62,11 +63,7 @@ func (service *userService) RegisterUser(user *models.User) (int64, string, erro
}
func (service *userService) VerifyUser(token *string) (*models.User, error) {
userID, err := service.repo.VerifyUserOfToken(token)
if err != nil {
return nil, err
}
user, err := service.repo.FindUserByID(userID)
user, err := service.repo.VerifyUserOfToken(token)
if err != nil {
return nil, err
}