add checkbox styling, driverslicence handling and validation

This commit is contained in:
Alex
2024-10-02 14:32:14 +02:00
parent 4ee18f21f2
commit cafe030e79
17 changed files with 303 additions and 44 deletions

View File

@@ -17,11 +17,12 @@ import (
)
type UserController struct {
Service services.UserServiceInterface
EmailService *services.EmailService
ConsentService services.ConsentServiceInterface
BankAccountService services.BankAccountServiceInterface
MembershipService services.MembershipServiceInterface
Service services.UserServiceInterface
EmailService *services.EmailService
ConsentService services.ConsentServiceInterface
BankAccountService services.BankAccountServiceInterface
MembershipService services.MembershipServiceInterface
DriversLicenceService services.DriversLicenceInterface
}
type RegistrationData struct {
@@ -129,10 +130,17 @@ func (uc *UserController) CurrentUserHandler(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving subscriptions."})
return
}
licenceCategories, err := uc.DriversLicenceService.GetAllCategories()
if err != nil {
logger.Error.Printf("Error retrieving licence categories: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving licence categories."})
return
}
logger.Error.Printf("licenceCategories: %#v", licenceCategories)
c.JSON(http.StatusOK, gin.H{
"user": user.Safe(),
"subscriptions": subscriptions,
"user": user.Safe(),
"subscriptions": subscriptions,
"licence_categories": licenceCategories,
})
}

View File

@@ -468,7 +468,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
u.FirstName = "John Updated"
u.LastName = "Doe Updated"
u.Phone = "01738484994"
u.DriversLicence.LicenceNumber = "NEWNUMBER"
u.DriversLicence.LicenceNumber = "B072RRE2I50"
},
expectedStatus: http.StatusAccepted,
},
@@ -482,7 +482,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
u.FirstName = "John Updated"
u.LastName = "Doe Updated"
u.Phone = "01738484994"
u.DriversLicence.LicenceNumber = "NEWNUMBER"
u.DriversLicence.LicenceNumber = "B072RRE2I50"
var licenceRepo repositories.DriversLicenceInterface = &repositories.DriversLicenceRepository{}
category, err := licenceRepo.FindCategoryByName("B")
assert.NoError(t, err)
@@ -500,7 +500,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
u.FirstName = "John Updated"
u.LastName = "Doe Updated"
u.Phone = "01738484994"
u.DriversLicence.LicenceNumber = "NEWNUMBER"
u.DriversLicence.LicenceNumber = "B072RRE2I50"
var licenceRepo repositories.DriversLicenceInterface = &repositories.DriversLicenceRepository{}
category, err := licenceRepo.FindCategoryByName("B")
category2, err := licenceRepo.FindCategoryByName("BE")
@@ -519,7 +519,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
u.FirstName = "John Updated"
u.LastName = "Doe Updated"
u.Phone = "01738484994"
u.DriversLicence.LicenceNumber = "NEWNUMBER"
u.DriversLicence.LicenceNumber = "B072RRE2I50"
u.DriversLicence.LicenceCategories = []models.LicenceCategory{}
},
expectedStatus: http.StatusAccepted,
@@ -534,7 +534,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
u.ID = 1
u.LastName = "Doe Updated"
u.Phone = "01738484994"
u.DriversLicence.LicenceNumber = "NEWNUMBER"
u.DriversLicence.LicenceNumber = "B072RRE2I50"
u.FirstName = "John Missing ID"
},
expectedStatus: http.StatusForbidden,
@@ -549,7 +549,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
u.Password = ""
u.LastName = "Doe Updated"
u.Phone = "01738484994"
u.DriversLicence.LicenceNumber = "NEWNUMBER"
u.DriversLicence.LicenceNumber = "B072RRE2I50"
u.Password = "NewPassword"
},
expectedStatus: http.StatusAccepted,
@@ -652,6 +652,9 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) {
assert.Equal(t, updatedUser.Membership.SubscriptionModelID, updatedUserFromDB.Membership.SubscriptionModelID, "Membership.SubscriptionModelID mismatch")
assert.Equal(t, updatedUser.Membership.ParentMembershipID, updatedUserFromDB.Membership.ParentMembershipID, "Membership.ParentMembershipID mismatch")
if updatedUser.DriversLicence.Status == 0 {
updatedUser.DriversLicence.Status = constants.UnverifiedStatus
}
assert.Equal(t, updatedUser.DriversLicence.Status, updatedUserFromDB.DriversLicence.Status, "DriversLicence.Status mismatch")
assert.Equal(t, updatedUser.DriversLicence.LicenceNumber, updatedUserFromDB.DriversLicence.LicenceNumber, "DriversLicence.LicenceNumber mismatch")
assert.Equal(t, updatedUser.DriversLicence.IssuedDate, updatedUserFromDB.DriversLicence.IssuedDate, "DriversLicence.IssuedDate mismatch")
@@ -1023,5 +1026,27 @@ func getTestUsers() []RegisterUserTest {
return user
})),
},
{
Name: "wrong driverslicence number, should fail",
WantResponse: http.StatusNotAcceptable,
WantDBData: map[string]interface{}{"email": "john.wronglicence.doe@example.com"},
Assert: false,
Input: GenerateInputJSON(customizeInput(func(user models.User) models.User {
user.Email = "john.wronglicence.doe@example.com"
user.DriversLicence.LicenceNumber = "AAAA12345AA"
return user
})),
},
{
Name: "Correct DriversLicence number, should pass",
WantResponse: http.StatusCreated,
WantDBData: map[string]interface{}{"email": "john.correctLicenceNumber@example.com"},
Assert: true,
Input: GenerateInputJSON(customizeInput(func(user models.User) models.User {
user.Email = "john.correctLicenceNumber@example.com"
user.DriversLicence.LicenceNumber = "B072RRE2I55"
return user
})),
},
}
}

View File

@@ -8,20 +8,15 @@ import (
type DriversLicence struct {
gorm.Model
Status int8 `json:"licence_status" validate:"omitempty,number"`
LicenceNumber string `json:"licence_number" validate:"safe_content"`
IssuedDate time.Time `json:"licence_issued_date" validate:"omitempty,lte"`
ExpirationDate time.Time `json:"licence_expiration_date" validate:"omitempty,gt"`
IssuingCountry string `json:"licence_country" validate:"safe_content"`
Status int8 `json:"status" validate:"omitempty,number"`
LicenceNumber string `json:"number" validate:"omitempty,euDriversLicence,safe_content"`
IssuedDate time.Time `json:"issued_date" validate:"omitempty,lte"`
ExpirationDate time.Time `json:"expiration_date" validate:"omitempty,gt"`
IssuingCountry string `json:"country" validate:"safe_content"`
LicenceCategories []LicenceCategory `json:"licence_categories" gorm:"many2many:licence_2_categories"`
}
type LicenceCategory struct {
gorm.Model
Category string `json:"licence_category" validate:"safe_content"`
Category string `json:"category" validate:"safe_content"`
}
// func (d *DriversLicence) BeforeCreate(tx *gorm.DB) (err error) {
// d.Status = constants.UnverifiedStatus
// return
// }

View File

@@ -98,5 +98,13 @@ func (u *User) Safe() map[string]interface{} {
"bic": u.BankAccount.BIC,
"mandate_reference": u.BankAccount.MandateReference,
},
"drivers_licence": map[string]interface{}{
"id": u.DriversLicence.ID,
"status": u.DriversLicence.Status,
"issued_date": u.DriversLicence.IssuedDate,
"expiration_date": u.DriversLicence.ExpirationDate,
"country": u.DriversLicence.IssuingCountry,
"licence_categories": u.DriversLicence.LicenceCategories,
},
}
}

View File

@@ -8,10 +8,16 @@ import (
type DriversLicenceInterface interface {
FindCategoryByName(categoryName string) (models.LicenceCategory, error)
FindCategoriesByIDs(ids []uint) ([]models.LicenceCategory, error)
GetAllCategories() ([]models.LicenceCategory, error)
}
type DriversLicenceRepository struct{}
func (r *DriversLicenceRepository) GetAllCategories() ([]models.LicenceCategory, error) {
var categories []models.LicenceCategory
err := database.DB.Find(&categories).Error
return categories, err
}
func (r *DriversLicenceRepository) FindCategoriesByIDs(ids []uint) ([]models.LicenceCategory, error) {
var categories []models.LicenceCategory
err := database.DB.Where("id IN ?", ids).Find(&categories).Error

View File

@@ -40,9 +40,10 @@ func Run() {
var userRepo repositories.UserRepositoryInterface = &repositories.UserRepository{}
var licenceRepo repositories.DriversLicenceInterface = &repositories.DriversLicenceRepository{}
driversLicenceService := &services.DriversLicenceService{Repo: licenceRepo}
userService := &services.UserService{Repo: userRepo, Licences: licenceRepo}
userController := &controllers.UserController{Service: userService, EmailService: emailService, ConsentService: consentService, BankAccountService: bankAccountService, MembershipService: membershipService}
userController := &controllers.UserController{Service: userService, EmailService: emailService, ConsentService: consentService, DriversLicenceService: driversLicenceService, BankAccountService: bankAccountService, MembershipService: membershipService}
membershipController := &controllers.MembershipController{Service: *membershipService}
contactController := &controllers.ContactController{EmailService: emailService}

View File

@@ -0,0 +1,18 @@
package services
import (
"GoMembership/internal/models"
"GoMembership/internal/repositories"
)
type DriversLicenceInterface interface {
GetAllCategories() ([]models.LicenceCategory, error)
}
type DriversLicenceService struct {
Repo repositories.DriversLicenceInterface
}
func (s *DriversLicenceService) GetAllCategories() ([]models.LicenceCategory, error) {
return s.Repo.GetAllCategories()
}

View File

@@ -35,6 +35,7 @@ type UserService struct {
func (service *UserService) UpdateUser(user *models.User, userRole int8) (*models.User, error) {
if err := validateUserData(user, userRole); err != nil {
logger.Info.Printf("UPDATING user: %#v", user)
logger.Error.Printf("Failed to validate user data: %v", err)
return nil, errors.ErrInvalidUserData
}
@@ -44,6 +45,10 @@ func (service *UserService) UpdateUser(user *models.User, userRole int8) (*model
}
user.UpdatedAt = time.Now()
if user.DriversLicence.Status == 0 {
// This is a new drivers licence
user.DriversLicence.Status = constants.UnverifiedStatus
}
updatedUser, err := service.Repo.UpdateUser(user)
@@ -71,6 +76,7 @@ func (service *UserService) RegisterUser(user *models.User) (uint, string, error
user.CreatedAt = time.Now()
user.UpdatedAt = time.Now()
user.PaymentStatus = constants.AwaitingPaymentStatus
// user.DriversLicence.Status = constants.UnverifiedStatus
user.BankAccount.MandateDateSigned = time.Now()
id, err := service.Repo.CreateUser(user)
@@ -162,13 +168,14 @@ func validateUserData(user *models.User, userRole int8) error {
validate.RegisterValidation("bic", utils.ValidateToTrue)
validate.RegisterValidation("subscriptionModel", utils.ValidateToTrue)
validate.RegisterValidation("iban", utils.ValidateToTrue)
validate.RegisterValidation("euDriversLicence", utils.ValidateToTrue)
} else {
validate.RegisterValidation("membershipField", utils.ValidateRequiredMembershipField)
validate.RegisterValidation("age", utils.AgeValidator)
validate.RegisterValidation("bic", utils.BICValidator)
validate.RegisterValidation("subscriptionModel", utils.SubscriptionModelValidator)
validate.RegisterValidation("iban", utils.IBANValidator)
validate.RegisterValidation("euDriversLicence", utils.ValidateDriversLicence)
}
return validate.Struct(user)
}

View File

@@ -9,6 +9,7 @@ import (
"reflect"
"regexp"
"slices"
"strconv"
"strings"
"time"
@@ -80,22 +81,16 @@ func ValidateRequiredMembershipField(fl validator.FieldLevel) bool {
// Get the value of the field specified by RequiredMembershipField
fieldValue := reflect.ValueOf(membership).FieldByName(fieldName)
logger.Info.Printf("Starting fieldValue Validation for %v: %#v", fieldName, fieldValue)
// Check if the fieldValue is valid
if !fieldValue.IsValid() {
return false
}
logger.Info.Printf("fieldValue is valid: %#v", fieldValue)
// Check if the fieldValue is a nil pointer
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
return false
}
logger.Info.Println("fieldValue is not a nil pointer")
// Ensure that the fieldValue is an uint
var fieldUint uint
if fieldValue.Kind() == reflect.Uint {
@@ -104,17 +99,12 @@ func ValidateRequiredMembershipField(fl validator.FieldLevel) bool {
return false
}
logger.Info.Println("fieldValue is a int")
var membershipIDs []uint
if err := database.DB.Model(&models.Membership{}).Pluck("id", &membershipIDs).Error; err != nil {
logger.Error.Fatalf("Couldn't get SubscriptionModel names: %#v", err)
return false
}
logger.Info.Printf("found ids of members: %#v", membershipIDs)
// logger.Info.Printf("FIELD_NAME: %#v\nVALUE: %#v", fieldName, fieldValue)
// Check if the field value is zero (empty)
return slices.Contains(membershipIDs, fieldUint)
}
@@ -134,3 +124,34 @@ func ValidateSafeContent(fl validator.FieldLevel) bool {
}
return true
}
func ValidateDriversLicence(fl validator.FieldLevel) bool {
fieldValue := fl.Field().String()
if len(fieldValue) != 11 {
return false
}
id, tenthChar := string(fieldValue[:9]), string(fieldValue[9])
if tenthChar == "X" {
tenthChar = "10"
}
tenthValue, _ := strconv.ParseInt(tenthChar, 10, 8)
// for readability
weights := []int{9, 8, 7, 6, 5, 4, 3, 2, 1}
sum := 0
for i := 0; i < 9; i++ {
char := string(id[i])
value, _ := strconv.ParseInt(char, 36, 64)
sum += int(value) * weights[i]
}
calcCheckDigit := sum % 11
if calcCheckDigit != int(tenthValue) {
return false
}
return true
}