Compare commits
5 Commits
490b29295f
...
2af4575ff2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2af4575ff2 | ||
|
|
560623788a | ||
|
|
5d55f5a8d9 | ||
|
|
28dfe7ecde | ||
|
|
741145b960 |
@@ -18,7 +18,7 @@ func main() {
|
||||
|
||||
config.LoadConfig()
|
||||
|
||||
db, err := database.Open(config.DB.Path, config.Recipients.AdminEmail)
|
||||
db, err := database.Open(config.DB.Path, config.Recipients.AdminEmail, config.Env == "development")
|
||||
if err != nil {
|
||||
logger.Error.Fatalf("Couldn't init database: %v", err)
|
||||
}
|
||||
|
||||
@@ -77,12 +77,14 @@ var Priviliges = struct {
|
||||
}
|
||||
|
||||
var Roles = struct {
|
||||
Opponent int8
|
||||
Supporter int8
|
||||
Member int8
|
||||
Viewer int8
|
||||
Editor int8
|
||||
Admin int8
|
||||
}{
|
||||
Opponent: -5,
|
||||
Supporter: 0,
|
||||
Member: 1,
|
||||
Viewer: 2,
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestMain(t *testing.T) {
|
||||
log.Fatalf("Error setting environment variable: %v", err)
|
||||
}
|
||||
config.LoadConfig()
|
||||
db, err := database.Open("test.db", config.Recipients.AdminEmail)
|
||||
db, err := database.Open("test.db", config.Recipients.AdminEmail, true)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create DB: %#v", err)
|
||||
}
|
||||
@@ -130,10 +130,18 @@ func TestMain(t *testing.T) {
|
||||
ZipCode: "12345",
|
||||
City: "SampleCity",
|
||||
Status: constants.ActiveStatus,
|
||||
RoleID: 8,
|
||||
}
|
||||
Password: "",
|
||||
Notes: "",
|
||||
RoleID: constants.Roles.Admin,
|
||||
Consents: nil,
|
||||
Verifications: nil,
|
||||
Membership: nil,
|
||||
BankAccount: nil,
|
||||
Licence: &models.Licence{
|
||||
Status: constants.UnverifiedStatus,
|
||||
}}
|
||||
admin.SetPassword("securepassword")
|
||||
database.DB.Create(&admin)
|
||||
admin.Create(db)
|
||||
validation.SetupValidators(db)
|
||||
t.Run("userController", func(t *testing.T) {
|
||||
testUserController(t)
|
||||
@@ -275,10 +283,9 @@ func getBaseUser() models.User {
|
||||
ZipCode: "25474",
|
||||
City: "Hasloh",
|
||||
Phone: "01738484993",
|
||||
BankAccount: models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
BankAccount: &models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: &models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
Licence: nil,
|
||||
ProfilePicture: "",
|
||||
Password: "passw@#$#%$!-ord123",
|
||||
Company: "",
|
||||
RoleID: 1,
|
||||
@@ -295,10 +302,9 @@ func getBaseSupporter() models.User {
|
||||
ZipCode: "25474",
|
||||
City: "Hasloh",
|
||||
Phone: "01738484993",
|
||||
BankAccount: models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
BankAccount: &models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: &models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
Licence: nil,
|
||||
ProfilePicture: "",
|
||||
Password: "passw@#$#%$!-ord123",
|
||||
Company: "",
|
||||
RoleID: 0,
|
||||
|
||||
@@ -31,8 +31,10 @@ func setupTestContext() (*TestContext, error) {
|
||||
testEmail := "john.doe@example.com"
|
||||
user, err := Uc.Service.FromEmail(&testEmail)
|
||||
if err != nil {
|
||||
logger.Error.Printf("error fetching user: %#v", err)
|
||||
return nil, err
|
||||
}
|
||||
logger.Error.Printf("found user: %#v", user)
|
||||
return &TestContext{
|
||||
router: gin.Default(),
|
||||
response: httptest.NewRecorder(),
|
||||
@@ -60,7 +62,6 @@ func testCreatePasswordHandler(t *testing.T) {
|
||||
req, _ := http.NewRequest("POST", "/password", bytes.NewBuffer(body))
|
||||
req.AddCookie(AdminCookie)
|
||||
tc.router.ServeHTTP(tc.response, req)
|
||||
logger.Error.Printf("Test results for %#v", t.Name())
|
||||
assert.Equal(t, http.StatusAccepted, tc.response.Code)
|
||||
assert.JSONEq(t, `{"message":"password_change_requested"}`, tc.response.Body.String())
|
||||
err = checkEmailDelivery(tc.user, true)
|
||||
|
||||
@@ -137,9 +137,7 @@ func (uc *UserController) DeleteUser(c *gin.Context) {
|
||||
}
|
||||
|
||||
type deleteData struct {
|
||||
User struct {
|
||||
ID uint `json:"id" binding:"required,numeric"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
var data deleteData
|
||||
@@ -148,13 +146,13 @@ func (uc *UserController) DeleteUser(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !requestUser.HasPrivilege(constants.Priviliges.Delete) && data.User.ID != requestUser.ID {
|
||||
if !requestUser.HasPrivilege(constants.Priviliges.Delete) && data.ID != requestUser.ID {
|
||||
utils.RespondWithError(c, errors.ErrNotAuthorized, "Not allowed to delete user", http.StatusForbidden, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Error.Printf("Deleting user: %v", data.User)
|
||||
if err := uc.Service.Delete(&data.User.ID); err != nil {
|
||||
logger.Error.Printf("Deleting user: %v", data)
|
||||
if err := uc.Service.Delete(&data.ID); err != nil {
|
||||
utils.HandleDeleteUserError(c, err)
|
||||
return
|
||||
}
|
||||
@@ -291,12 +289,14 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
|
||||
LastName: regData.User.LastName,
|
||||
Email: regData.User.Email,
|
||||
ConsentType: "TermsOfService",
|
||||
UserID: regData.User.ID,
|
||||
},
|
||||
{
|
||||
FirstName: regData.User.FirstName,
|
||||
LastName: regData.User.LastName,
|
||||
Email: regData.User.Email,
|
||||
ConsentType: "Privacy",
|
||||
UserID: regData.User.ID,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,6 @@ func testUserController(t *testing.T) {
|
||||
database.DB.Model(&models.User{}).Where("email = ?", "john.doe@example.com").Update("status", constants.ActiveStatus)
|
||||
loginEmail := testLoginHandler(t)
|
||||
testCurrentUserHandler(t, loginEmail)
|
||||
|
||||
// creating a admin cookie
|
||||
c, w, _ := GetMockedJSONContext([]byte(`{
|
||||
"email": "admin@example.com",
|
||||
@@ -402,7 +401,6 @@ func validateUser(assert bool, wantDBData map[string]interface{}) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error in database ops: %#v", err)
|
||||
}
|
||||
|
||||
if assert != (len(*users) != 0) {
|
||||
return fmt.Errorf("User entry query didn't met expectation: %v != %#v", assert, *users)
|
||||
}
|
||||
@@ -575,7 +573,7 @@ func testUpdateUser(t *testing.T) {
|
||||
var licenceRepo repositories.LicenceInterface = &repositories.LicenceRepository{}
|
||||
category, err := licenceRepo.FindCategoryByName("B")
|
||||
assert.NoError(t, err)
|
||||
u.Licence.Categories = []models.Category{category}
|
||||
u.Licence.Categories = []*models.Category{&category}
|
||||
},
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
@@ -594,7 +592,7 @@ func testUpdateUser(t *testing.T) {
|
||||
category, err := licenceRepo.FindCategoryByName("A")
|
||||
category2, err := licenceRepo.FindCategoryByName("BE")
|
||||
assert.NoError(t, err)
|
||||
u.Licence.Categories = []models.Category{category, category2}
|
||||
u.Licence.Categories = []*models.Category{&category, &category2}
|
||||
},
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
@@ -612,7 +610,7 @@ func testUpdateUser(t *testing.T) {
|
||||
var licenceRepo repositories.LicenceInterface = &repositories.LicenceRepository{}
|
||||
category, err := licenceRepo.FindCategoryByName("A")
|
||||
assert.NoError(t, err)
|
||||
u.Licence.Categories = []models.Category{category}
|
||||
u.Licence.Categories = []*models.Category{&category}
|
||||
},
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
@@ -627,7 +625,7 @@ func testUpdateUser(t *testing.T) {
|
||||
u.LastName = "Doe Updated"
|
||||
u.Phone = "01738484994"
|
||||
u.Licence.Number = "B072RRE2I50"
|
||||
u.Licence.Categories = []models.Category{}
|
||||
u.Licence.Categories = []*models.Category{}
|
||||
},
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
@@ -806,11 +804,9 @@ func testUpdateUser(t *testing.T) {
|
||||
assert.Equal(t, updatedUser.Company, updatedUserFromDB.Company, "Company mismatch")
|
||||
assert.Equal(t, updatedUser.Phone, updatedUserFromDB.Phone, "Phone mismatch")
|
||||
assert.Equal(t, updatedUser.Notes, updatedUserFromDB.Notes, "Notes mismatch")
|
||||
assert.Equal(t, updatedUser.ProfilePicture, updatedUserFromDB.ProfilePicture, "ProfilePicture mismatch")
|
||||
assert.Equal(t, updatedUser.Address, updatedUserFromDB.Address, "Address mismatch")
|
||||
assert.Equal(t, updatedUser.ZipCode, updatedUserFromDB.ZipCode, "ZipCode mismatch")
|
||||
assert.Equal(t, updatedUser.City, updatedUserFromDB.City, "City mismatch")
|
||||
assert.Equal(t, updatedUser.PaymentStatus, updatedUserFromDB.PaymentStatus, "PaymentStatus mismatch")
|
||||
assert.Equal(t, updatedUser.Status, updatedUserFromDB.Status, "Status mismatch")
|
||||
assert.Equal(t, updatedUser.RoleID, updatedUserFromDB.RoleID, "RoleID mismatch")
|
||||
|
||||
@@ -839,8 +835,17 @@ func testUpdateUser(t *testing.T) {
|
||||
assert.Equal(t, updatedUser.Licence.IssuingCountry, updatedUserFromDB.Licence.IssuingCountry, "Licence.IssuingCountry mismatch")
|
||||
}
|
||||
|
||||
// For slices or more complex nested structures, you might want to use deep equality checks
|
||||
assert.ElementsMatch(t, updatedUser.Consents, updatedUserFromDB.Consents, "Consents mismatch")
|
||||
if len(updatedUser.Consents) > 0 {
|
||||
for i := range updatedUser.Consents {
|
||||
assert.Equal(t, updatedUser.Consents[i].ConsentType, updatedUserFromDB.Consents[i].ConsentType, "ConsentType mismatch at index %d", i)
|
||||
assert.Equal(t, updatedUser.Consents[i].Email, updatedUserFromDB.Consents[i].Email, "ConsentEmail mismatch at index %d", i)
|
||||
assert.Equal(t, updatedUser.Consents[i].FirstName, updatedUserFromDB.Consents[i].FirstName, "ConsentFirstName mismatch at index %d", i)
|
||||
assert.Equal(t, updatedUser.Consents[i].LastName, updatedUserFromDB.Consents[i].LastName, "ConsentLastName mismatch at index %d", i)
|
||||
assert.Equal(t, updatedUser.Consents[i].UserID, updatedUserFromDB.Consents[i].UserID, "Consent UserId mismatch at index %d", i)
|
||||
}
|
||||
} else {
|
||||
assert.Emptyf(t, updatedUserFromDB.Licence.Categories, "Categories aren't empty when they should")
|
||||
}
|
||||
if len(updatedUser.Licence.Categories) > 0 {
|
||||
for i := range updatedUser.Licence.Categories {
|
||||
assert.Equal(t, updatedUser.Licence.Categories[i].Name, updatedUserFromDB.Licence.Categories[i].Name, "Category Category mismatch at index %d", i)
|
||||
@@ -1272,7 +1277,7 @@ func getTestUsers() []RegisterUserTest {
|
||||
{
|
||||
Name: "Correct Licence number, should pass",
|
||||
WantResponse: http.StatusCreated,
|
||||
WantDBData: map[string]interface{}{"email": "john.correctLicenceNumber@example.com"},
|
||||
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"
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"GoMembership/pkg/logger"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/alexedwards/argon2id"
|
||||
@@ -15,27 +17,55 @@ import (
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
func Open(dbPath string, adminMail string) (*gorm.DB, error) {
|
||||
func Open(dbPath string, adminMail string, debug bool) (*gorm.DB, error) {
|
||||
// Add foreign key support and WAL journal mode to DSN
|
||||
dsn := fmt.Sprintf("%s?_foreign_keys=1&_journal_mode=WAL", dbPath)
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
||||
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
|
||||
// Enable PrepareStmt for better performance
|
||||
PrepareStmt: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to connect database: %w", err)
|
||||
}
|
||||
|
||||
// Verify foreign key support is enabled
|
||||
var foreignKeyEnabled int
|
||||
if err := db.Raw("PRAGMA foreign_keys").Scan(&foreignKeyEnabled).Error; err != nil {
|
||||
return nil, fmt.Errorf("foreign key check failed: %w", err)
|
||||
}
|
||||
if foreignKeyEnabled != 1 {
|
||||
return nil, errors.New("SQLite foreign key constraints not enabled")
|
||||
}
|
||||
|
||||
if debug {
|
||||
db = db.Debug()
|
||||
}
|
||||
|
||||
// Configure connection pool
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get DB instance: %w", err)
|
||||
}
|
||||
sqlDB.SetMaxOpenConns(1) // Required for SQLite in production
|
||||
sqlDB.SetMaxIdleConns(1)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
if err := db.AutoMigrate(
|
||||
&models.User{},
|
||||
&models.SubscriptionModel{},
|
||||
&models.Membership{},
|
||||
&models.Consent{},
|
||||
&models.Verification{},
|
||||
&models.BankAccount{},
|
||||
&models.Licence{},
|
||||
&models.Category{},
|
||||
&models.Insurance{},
|
||||
&models.Car{},
|
||||
&models.Location{},
|
||||
&models.Damage{},
|
||||
&models.BankAccount{}); err != nil {
|
||||
logger.Error.Fatalf("Couldn't create database: %v", err)
|
||||
return nil, err
|
||||
&models.Insurance{},
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to migrate database: %w", err)
|
||||
}
|
||||
|
||||
logger.Info.Print("Opened DB")
|
||||
@@ -78,14 +108,11 @@ func Open(dbPath string, adminMail string) (*gorm.DB, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
admin, err := createAdmin(adminMail, createdModel.ID)
|
||||
admin, err := createAdmin(adminMail)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := db.Session(&gorm.Session{FullSaveAssociations: true}).Create(&admin)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
admin.Create(db)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
@@ -125,7 +152,7 @@ func createLicenceCategories() []models.Category {
|
||||
|
||||
// TODO: Landing page to create an admin
|
||||
|
||||
func createAdmin(userMail string, subscriptionModelID uint) (*models.User, error) {
|
||||
func createAdmin(userMail string) (*models.User, error) {
|
||||
passwordBytes := make([]byte, 12)
|
||||
_, err := rand.Read(passwordBytes)
|
||||
if err != nil {
|
||||
@@ -146,26 +173,24 @@ func createAdmin(userMail string, subscriptionModelID uint) (*models.User, error
|
||||
logger.Error.Print("==============================================================")
|
||||
|
||||
return &models.User{
|
||||
FirstName: "ad",
|
||||
LastName: "min",
|
||||
FirstName: "Ad",
|
||||
LastName: "Min",
|
||||
DateOfBirth: time.Now().AddDate(-20, 0, 0),
|
||||
Password: hash,
|
||||
Address: "Downhill 4",
|
||||
ZipCode: "99999",
|
||||
City: "TechTown",
|
||||
Phone: "0123455678",
|
||||
Company: "",
|
||||
Address: "",
|
||||
ZipCode: "",
|
||||
City: "",
|
||||
Phone: "",
|
||||
Notes: "",
|
||||
Email: userMail,
|
||||
Status: constants.ActiveStatus,
|
||||
RoleID: constants.Roles.Admin,
|
||||
Membership: models.Membership{
|
||||
Status: constants.DisabledStatus,
|
||||
StartDate: time.Now(),
|
||||
SubscriptionModelID: subscriptionModelID,
|
||||
},
|
||||
BankAccount: models.BankAccount{},
|
||||
Licence: &models.Licence{
|
||||
Status: constants.UnverifiedStatus,
|
||||
},
|
||||
Consents: nil,
|
||||
Verifications: nil,
|
||||
Membership: nil,
|
||||
BankAccount: nil,
|
||||
Licence: nil,
|
||||
}, nil
|
||||
//"DE49700500000008447644", //fake
|
||||
}
|
||||
|
||||
@@ -1,15 +1,50 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type BankAccount struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
MandateDateSigned time.Time `gorm:"not null" json:"mandate_date_signed"`
|
||||
UserID uint `gorm:"index" json:"user_id"`
|
||||
MandateDateSigned time.Time `json:"mandate_date_signed"`
|
||||
Bank string `json:"bank_name" binding:"safe_content"`
|
||||
AccountHolderName string `json:"account_holder_name" binding:"safe_content"`
|
||||
IBAN string `json:"iban" binding:"safe_content"`
|
||||
BIC string `json:"bic" binding:"safe_content"`
|
||||
MandateReference string `gorm:"not null" json:"mandate_reference" binding:"safe_content"`
|
||||
MandateReference string `json:"mandate_reference" binding:"safe_content"`
|
||||
}
|
||||
|
||||
func (b *BankAccount) Create(db *gorm.DB) error {
|
||||
// b.ID = 0
|
||||
// only the children the belongs to association gets a reference id
|
||||
if err := db.Create(b).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info.Printf("BankAccount created: %#v", b)
|
||||
return db.First(b, b.ID).Error // Refresh the object with all associations
|
||||
|
||||
}
|
||||
|
||||
func (b *BankAccount) Update(db *gorm.DB) error {
|
||||
var existingBankAccount BankAccount
|
||||
|
||||
logger.Info.Printf("updating BankAccount: %#v", b)
|
||||
if err := db.First(&existingBankAccount, b.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := db.Model(&existingBankAccount).Updates(b).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return db.First(b, b.ID).Error
|
||||
}
|
||||
|
||||
func (b *BankAccount) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&b).Error
|
||||
}
|
||||
|
||||
48
go-backend/internal/models/category.go
Normal file
48
go-backend/internal/models/category.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Category struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"category" binding:"safe_content"`
|
||||
}
|
||||
|
||||
func (c *Category) Create(db *gorm.DB) error {
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Create the base User record (omit associations to handle them separately)
|
||||
if err := tx.Create(c).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info.Printf("Category created: %#v", c)
|
||||
// Preload all associations to return the fully populated User
|
||||
return tx.
|
||||
First(c, c.ID).Error // Refresh the user object with all associations
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Category) Update(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingCategory Category
|
||||
|
||||
logger.Info.Printf("updating Category: %#v", c)
|
||||
if err := tx.First(&existingCategory, c.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&existingCategory).Updates(c).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.First(c, c.ID).Error
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (c *Category) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&c).Error
|
||||
}
|
||||
@@ -1,17 +1,55 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Consent struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
FirstName string `gorm:"not null" json:"first_name" binding:"safe_content"`
|
||||
LastName string `gorm:"not null" json:"last_name" binding:"safe_content"`
|
||||
Email string `json:"email" binding:"email,safe_content"`
|
||||
ConsentType string `gorm:"not null" json:"consent_type" binding:"safe_content"`
|
||||
ID uint `gorm:"primaryKey"`
|
||||
User User
|
||||
UserID uint
|
||||
UserID uint `gorm:"not null" json:"user_id"`
|
||||
}
|
||||
|
||||
func (c *Consent) BeforeSave(tx *gorm.DB) (err error) {
|
||||
c.Email = strings.ToLower(c.Email)
|
||||
return nil
|
||||
}
|
||||
func (c *Consent) Create(db *gorm.DB) error {
|
||||
if err := db.Create(c).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info.Printf("Consent created: %#v", c)
|
||||
return db.First(c, c.ID).Error // Refresh the user object with all associations
|
||||
}
|
||||
|
||||
func (c *Consent) Update(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingConsent Consent
|
||||
|
||||
logger.Info.Printf("updating Consent: %#v", c)
|
||||
if err := tx.First(&existingConsent, c.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&existingConsent).Updates(c).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.First(c, c.ID).Error
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (c *Consent) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&c).Error
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Licence struct {
|
||||
@@ -14,10 +18,49 @@ type Licence struct {
|
||||
IssuedDate time.Time `json:"issued_date" binding:"omitempty"`
|
||||
ExpirationDate time.Time `json:"expiration_date" binding:"omitempty"`
|
||||
IssuingCountry string `json:"country" binding:"safe_content"`
|
||||
Categories []Category `json:"categories" gorm:"many2many:licence_2_categories"`
|
||||
Categories []*Category `json:"categories" gorm:"many2many:licence_2_categories"`
|
||||
}
|
||||
|
||||
type Category struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"category" binding:"safe_content"`
|
||||
func (l *Licence) BeforeSafe(tx *gorm.DB) error {
|
||||
if err := tx.Model(l).Association("Categories").Replace(l.Categories); err != nil {
|
||||
return fmt.Errorf("failed to link categories: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Licence) Create(db *gorm.DB) error {
|
||||
if err := db.Omit("Categories").Create(l).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := db.Model(&l).Association("Categories").Replace(l.Categories); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info.Printf("Licence created: %#v", l)
|
||||
return db.Preload("Categories").First(l, l.ID).Error // Refresh the object with Categories
|
||||
}
|
||||
|
||||
func (l *Licence) Update(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingLicence Licence
|
||||
|
||||
logger.Info.Printf("updating Licence: %#v", l)
|
||||
if err := tx.First(&existingLicence, l.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&existingLicence).Updates(l).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.First(l, l.ID).Error
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (l *Licence) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&l).Error
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Membership struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
UserID uint `gorm:"index" json:"user_id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
StartDate time.Time `json:"start_date"`
|
||||
@@ -11,5 +18,41 @@ type Membership struct {
|
||||
SubscriptionModel SubscriptionModel `gorm:"foreignKey:SubscriptionModelID" json:"subscription_model"`
|
||||
SubscriptionModelID uint `json:"subsription_model_id"`
|
||||
ParentMembershipID uint `json:"parent_member_id" binding:"omitempty,omitnil,number"`
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
func (m *Membership) BeforeSave(tx *gorm.DB) error {
|
||||
m.SubscriptionModelID = m.SubscriptionModel.ID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Membership) Create(db *gorm.DB) error {
|
||||
if err := db.Create(m).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info.Printf("Membership created: %#v", m)
|
||||
|
||||
return db.Preload("SubscriptionModel").First(m, m.ID).Error // Refresh the user object with SubscriptionModel
|
||||
}
|
||||
|
||||
func (m *Membership) Update(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingMembership Membership
|
||||
|
||||
logger.Info.Printf("updating Membership: %#v", m)
|
||||
if err := tx.First(&existingMembership, m.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&existingMembership).Updates(m).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.First(m, m.ID).Error
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (m *Membership) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&m).Error
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SubscriptionModel struct {
|
||||
@@ -17,3 +20,39 @@ type SubscriptionModel struct {
|
||||
IncludedPerYear int16 `json:"included_hours_per_year"`
|
||||
IncludedPerMonth int16 `json:"included_hours_per_month"`
|
||||
}
|
||||
|
||||
func (s *SubscriptionModel) Create(db *gorm.DB) error {
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Create the base User record (omit associations to handle them separately)
|
||||
if err := tx.Create(s).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info.Printf("SubscriptionModel created: %#v", s)
|
||||
// Preload all associations to retuvn the fully populated User
|
||||
return tx.
|
||||
First(s, s.ID).Error // Refresh the user object with all associations
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SubscriptionModel) Update(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingSubscriptionModel SubscriptionModel
|
||||
|
||||
logger.Info.Printf("updating SubscriptionModel: %#v", s)
|
||||
if err := tx.First(&existingSubscriptionModel, s.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&existingSubscriptionModel).Updates(s).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.First(s, s.ID).Error
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (s *SubscriptionModel) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&s).Error
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"GoMembership/pkg/logger"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alexedwards/argon2id"
|
||||
@@ -18,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
@@ -30,32 +31,31 @@ type User struct {
|
||||
Password string `json:"password" binding:"safe_content"`
|
||||
Email string `gorm:"uniqueIndex:idx_users_email,not null" json:"email" binding:"required,email,safe_content"`
|
||||
LastName string `gorm:"not null" json:"last_name" binding:"required,safe_content"`
|
||||
ProfilePicture string `json:"profile_picture" binding:"omitempty,omitnil,image,safe_content"`
|
||||
Address string `gorm:"not null" json:"address" binding:"required,safe_content"`
|
||||
ZipCode string `gorm:"not null" json:"zip_code" binding:"required,alphanum,safe_content"`
|
||||
City string `form:"not null" json:"city" binding:"required,alphaunicode,safe_content"`
|
||||
Consents []Consent `gorm:"constraint:OnUpdate:CASCADE"`
|
||||
BankAccount BankAccount `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"bank_account"`
|
||||
BankAccountID uint
|
||||
Verifications *[]Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||
Membership Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"membership"`
|
||||
MembershipID uint
|
||||
BankAccount *BankAccount `gorm:"foreignkey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"bank_account"`
|
||||
Verifications []Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||
Membership *Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"membership"`
|
||||
Licence *Licence `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"licence"`
|
||||
LicenceID uint
|
||||
PaymentStatus int8 `json:"payment_status"`
|
||||
Status int8 `json:"status"`
|
||||
RoleID int8 `json:"role_id"`
|
||||
}
|
||||
|
||||
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
|
||||
if u.BankAccount.ID != 0 && u.BankAccount.MandateReference == "" {
|
||||
mandateReference := u.GenerateMandateReference()
|
||||
|
||||
return tx.Model(&u.BankAccount).Update("MandateReference", mandateReference).Error
|
||||
if u.BankAccount != nil && u.BankAccount.MandateReference == "" {
|
||||
u.BankAccount.MandateReference = u.GenerateMandateReference()
|
||||
u.BankAccount.Update(tx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) BeforeSave(tx *gorm.DB) (err error) {
|
||||
u.Email = strings.ToLower(u.Email)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) GenerateMandateReference() string {
|
||||
return fmt.Sprintf("%s%d%s", time.Now().Format("20060102"), u.ID, u.BankAccount.IBAN)
|
||||
}
|
||||
@@ -86,29 +86,128 @@ func (u *User) Delete(db *gorm.DB) error {
|
||||
}
|
||||
|
||||
func (u *User) Create(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Create the base User record (omit associations to handle them separately)
|
||||
if err := tx.Create(u).Error; err != nil {
|
||||
if err := tx.Preload(clause.Associations).Create(u).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Replace associated Categories (assumes Categories already exist)
|
||||
if u.Licence != nil && len(u.Licence.Categories) > 0 {
|
||||
if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
logger.Info.Printf("user created: %#v", u.Safe())
|
||||
// Preload all associations to return the fully populated User
|
||||
return tx.
|
||||
Preload("Membership").
|
||||
Preload("Membership.SubscriptionModel").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
First(u, u.ID).Error // Refresh the user object with all associations
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// return db.Transaction(func(tx *gorm.DB) error {
|
||||
|
||||
// // Initialize slices/pointers if nil
|
||||
// if u.Verifications == nil {
|
||||
// u.Verifications = &[]Verification{}
|
||||
// }
|
||||
|
||||
// // Create base user first
|
||||
// if err := tx.Omit(clause.Associations).Create(u).Error; err != nil {
|
||||
// return fmt.Errorf("failed to create user: %w", err)
|
||||
// }
|
||||
|
||||
// // Handle BankAccount
|
||||
// if u.BankAccount != (BankAccount{}) {
|
||||
// u.BankAccount.MandateReference = u.GenerateMandateReference()
|
||||
// if err := tx.Create(&u.BankAccount).Error; err != nil {
|
||||
// return fmt.Errorf("failed to create bank account: %w", err)
|
||||
// }
|
||||
// if err := tx.Model(u).Update("bank_account_id", u.BankAccount.ID).Error; err != nil {
|
||||
// return fmt.Errorf("failed to link bank account: %w", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Handle Membership and SubscriptionModel
|
||||
// if u.Membership != (Membership{}) {
|
||||
// if err := tx.Create(&u.Membership).Error; err != nil {
|
||||
// return fmt.Errorf("failed to create membership: %w", err)
|
||||
// }
|
||||
// if err := tx.Model(u).Update("membership_id", u.Membership.ID).Error; err != nil {
|
||||
// return fmt.Errorf("failed to link membership: %w", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Handle Licence and Categories
|
||||
// if u.Licence != nil {
|
||||
// u.Licence.UserID = u.ID
|
||||
// if err := tx.Create(u.Licence).Error; err != nil {
|
||||
// return fmt.Errorf("failed to create licence: %w", err)
|
||||
// }
|
||||
|
||||
// if len(u.Licence.Categories) > 0 {
|
||||
// if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
|
||||
// return fmt.Errorf("failed to link categories: %w", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// if err := tx.Model(u).Update("licence_id", u.Licence.ID).Error; err != nil {
|
||||
// return fmt.Errorf("failed to link licence: %w", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Handle Consents
|
||||
// for i := range u.Consents {
|
||||
// u.Consents[i].UserID = u.ID
|
||||
// }
|
||||
// if len(u.Consents) > 0 {
|
||||
// if err := tx.Create(&u.Consents).Error; err != nil {
|
||||
// return fmt.Errorf("failed to create consents: %w", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Handle Verifications
|
||||
// for i := range *u.Verifications {
|
||||
// (*u.Verifications)[i].UserID = u.ID
|
||||
// }
|
||||
// if len(*u.Verifications) > 0 {
|
||||
// if err := tx.Create(u.Verifications).Error; err != nil {
|
||||
// return fmt.Errorf("failed to create verifications: %w", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Reload the complete user with all associations
|
||||
// return tx.Preload(clause.Associations).
|
||||
// Preload("Membership.SubscriptionModel").
|
||||
// Preload("Licence.Categories").
|
||||
// First(u, u.ID).Error
|
||||
// })
|
||||
// }
|
||||
|
||||
// func (u *User) Create(db *gorm.DB) error {
|
||||
// return db.Transaction(func(tx *gorm.DB) error {
|
||||
// // Create the base User record (omit associations to handle them separately)
|
||||
// if err := tx.Create(u).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// for i := range u.Consents {
|
||||
// u.Consents[i].UserID = u.ID
|
||||
// }
|
||||
|
||||
// for i := range *u.Verifications {
|
||||
// (*u.Verifications)[i].UserID = u.ID
|
||||
// }
|
||||
|
||||
// if err := tx.Session(&gorm.Session{FullSaveAssociations: true}).Updates(u).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// // Replace associated Categories (assumes Categories already exist)
|
||||
// if u.Licence != nil && len(u.Licence.Categories) > 0 {
|
||||
// if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// logger.Info.Printf("user created: %#v", u.Safe())
|
||||
// // Preload all associations to return the fully populated User
|
||||
// return tx.
|
||||
// Preload(clause.Associations).
|
||||
// Preload("Membership.SubscriptionModel").
|
||||
// Preload("Licence.Categories").
|
||||
// First(u, u.ID).Error // Refresh the user object with all associations
|
||||
// })
|
||||
// }
|
||||
|
||||
func (u *User) Update(db *gorm.DB) error {
|
||||
|
||||
err := db.Transaction(func(tx *gorm.DB) error {
|
||||
@@ -117,16 +216,11 @@ func (u *User) Update(db *gorm.DB) error {
|
||||
|
||||
logger.Info.Printf("updating user: %#v", u)
|
||||
if err := tx.
|
||||
Preload("Membership").
|
||||
Preload("Membership.SubscriptionModel").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
Preload("Verifications").
|
||||
First(&existingUser, u.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// Update the user's main fields
|
||||
result := tx.Session(&gorm.Session{FullSaveAssociations: true}).Omit("Password", "Membership", "Licence", "Verifications").Updates(u)
|
||||
result := tx.Session(&gorm.Session{FullSaveAssociations: true}).Omit("Password", "Verifications", "Licence.Categories").Updates(u)
|
||||
if result.Error != nil {
|
||||
logger.Error.Printf("User update error in update user: %#v", result.Error)
|
||||
return result.Error
|
||||
@@ -143,28 +237,28 @@ func (u *User) Update(db *gorm.DB) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Update the Membership if provided
|
||||
if u.Membership.ID != 0 {
|
||||
if err := tx.Model(&existingUser.Membership).Updates(u.Membership).Error; err != nil {
|
||||
logger.Error.Printf("Membership update error in update user: %#v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if u.Licence != nil {
|
||||
u.Licence.UserID = existingUser.ID
|
||||
// // Update the Membership if provided
|
||||
// if u.Membership.ID != 0 {
|
||||
// if err := tx.Model(&existingUser.Membership).Updates(u.Membership).Where("id = ?", existingUser.Membership.ID).Error; err != nil {
|
||||
// logger.Error.Printf("Membership update error in update user: %#v", err)
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// if u.Licence != nil {
|
||||
// u.Licence.UserID = existingUser.ID
|
||||
|
||||
if err := tx.Save(u.Licence).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := tx.Save(u.Licence).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
if err := tx.Model(&existingUser).Update("LicenceID", u.Licence.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := tx.Model(&existingUser).Update("LicenceID", u.Licence.ID).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// if u.Licence != nil {
|
||||
// if existingUser.Licence == nil || existingUser.LicenceID == 0 {
|
||||
// u.Licence.UserID = existingUser.ID // Ensure Licence belongs to User
|
||||
@@ -187,7 +281,13 @@ func (u *User) Update(db *gorm.DB) error {
|
||||
// }
|
||||
|
||||
if u.Verifications != nil {
|
||||
if err := tx.Save(*u.Verifications).Error; err != nil {
|
||||
if err := tx.Save(u.Verifications).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if u.Licence != nil {
|
||||
if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -199,11 +299,9 @@ func (u *User) Update(db *gorm.DB) error {
|
||||
}
|
||||
|
||||
return db.
|
||||
Preload("Membership").
|
||||
Preload(clause.Associations).
|
||||
Preload("Membership.SubscriptionModel").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
Preload("Verifications").
|
||||
First(&u, u.ID).Error
|
||||
}
|
||||
|
||||
@@ -211,11 +309,8 @@ func (u *User) FromID(db *gorm.DB, userID *uint) error {
|
||||
var user User
|
||||
result := db.
|
||||
Preload(clause.Associations).
|
||||
Preload("Membership").
|
||||
Preload("Membership.SubscriptionModel").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
Preload("Verifications").
|
||||
First(&user, userID)
|
||||
if result.Error != nil {
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
@@ -231,11 +326,8 @@ func (u *User) FromEmail(db *gorm.DB, email *string) error {
|
||||
var user User
|
||||
result := db.
|
||||
Preload(clause.Associations).
|
||||
Preload("Membership").
|
||||
Preload("Membership.SubscriptionModel").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
Preload("Verifications").
|
||||
Where("email = ?", email).First(&user)
|
||||
if result.Error != nil {
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
@@ -284,7 +376,7 @@ func (u *User) IsSupporter() bool {
|
||||
|
||||
func (u *User) SetVerification(verificationType string) (*Verification, error) {
|
||||
if u.Verifications == nil {
|
||||
u.Verifications = new([]Verification)
|
||||
u.Verifications = []Verification{}
|
||||
}
|
||||
token, err := utils.GenerateVerificationToken()
|
||||
if err != nil {
|
||||
@@ -295,10 +387,10 @@ func (u *User) SetVerification(verificationType string) (*Verification, error) {
|
||||
VerificationToken: token,
|
||||
Type: verificationType,
|
||||
}
|
||||
if vi := slices.IndexFunc(*u.Verifications, func(vsl Verification) bool { return vsl.Type == v.Type }); vi > -1 {
|
||||
(*u.Verifications)[vi] = v
|
||||
if vi := slices.IndexFunc(u.Verifications, func(vsl Verification) bool { return vsl.Type == v.Type }); vi > -1 {
|
||||
u.Verifications[vi] = v
|
||||
} else {
|
||||
*u.Verifications = append(*u.Verifications, v)
|
||||
u.Verifications = append(u.Verifications, v)
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
@@ -307,11 +399,11 @@ func (u *User) GetVerification(verificationType string) (*Verification, error) {
|
||||
if u.Verifications == nil {
|
||||
return nil, errors.ErrNoData
|
||||
}
|
||||
vi := slices.IndexFunc(*u.Verifications, func(vsl Verification) bool { return vsl.Type == verificationType })
|
||||
vi := slices.IndexFunc(u.Verifications, func(vsl Verification) bool { return vsl.Type == verificationType })
|
||||
if vi == -1 {
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
return &(*u.Verifications)[vi], nil
|
||||
return &u.Verifications[vi], nil
|
||||
}
|
||||
|
||||
func (u *User) Verify(token string, verificationType string) bool {
|
||||
@@ -320,7 +412,7 @@ func (u *User) Verify(token string, verificationType string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
vi := slices.IndexFunc(*u.Verifications, func(vsl Verification) bool {
|
||||
vi := slices.IndexFunc(u.Verifications, func(vsl Verification) bool {
|
||||
return vsl.Type == verificationType && vsl.VerificationToken == token
|
||||
})
|
||||
|
||||
@@ -329,32 +421,22 @@ func (u *User) Verify(token string, verificationType string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if (*u.Verifications)[vi].VerifiedAt != nil {
|
||||
logger.Error.Printf("VerifiedAt is not nil, already verified?: %#v", (*u.Verifications)[vi])
|
||||
if u.Verifications[vi].VerifiedAt != nil {
|
||||
logger.Error.Printf("VerifiedAt is not nil, already verified?: %#v", u.Verifications[vi])
|
||||
return false
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
(*u.Verifications)[vi].VerifiedAt = &t
|
||||
u.Verifications[vi].VerifiedAt = &t
|
||||
return true
|
||||
}
|
||||
|
||||
func (u *User) Safe() map[string]interface{} {
|
||||
result := map[string]interface{}{
|
||||
"email": u.Email,
|
||||
"first_name": u.FirstName,
|
||||
"last_name": u.LastName,
|
||||
"phone": u.Phone,
|
||||
"notes": u.Notes,
|
||||
"address": u.Address,
|
||||
"zip_code": u.ZipCode,
|
||||
"city": u.City,
|
||||
"status": u.Status,
|
||||
"id": u.ID,
|
||||
"role_id": u.RoleID,
|
||||
"company": u.Company,
|
||||
"dateofbirth": u.DateOfBirth,
|
||||
"membership": map[string]interface{}{
|
||||
var membership map[string]interface{} = nil
|
||||
var licence map[string]interface{} = nil
|
||||
var bankAccount map[string]interface{} = nil
|
||||
if u.Membership != nil {
|
||||
membership = map[string]interface{}{
|
||||
"id": u.Membership.ID,
|
||||
"start_date": u.Membership.StartDate,
|
||||
"end_date": u.Membership.EndDate,
|
||||
@@ -369,23 +451,11 @@ func (u *User) Safe() map[string]interface{} {
|
||||
"included_per_year": u.Membership.SubscriptionModel.IncludedPerYear,
|
||||
"included_per_month": u.Membership.SubscriptionModel.IncludedPerMonth,
|
||||
},
|
||||
},
|
||||
"licence": map[string]interface{}{
|
||||
"id": 0,
|
||||
},
|
||||
"bank_account": map[string]interface{}{
|
||||
"id": u.BankAccount.ID,
|
||||
"mandate_date_signed": u.BankAccount.MandateDateSigned,
|
||||
"bank": u.BankAccount.Bank,
|
||||
"account_holder_name": u.BankAccount.AccountHolderName,
|
||||
"iban": u.BankAccount.IBAN,
|
||||
"bic": u.BankAccount.BIC,
|
||||
"mandate_reference": u.BankAccount.MandateReference,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if u.Licence != nil {
|
||||
result["licence"] = map[string]interface{}{
|
||||
licence = map[string]interface{}{
|
||||
"id": u.Licence.ID,
|
||||
"number": u.Licence.Number,
|
||||
"status": u.Licence.Status,
|
||||
@@ -396,6 +466,36 @@ func (u *User) Safe() map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
if u.BankAccount != nil {
|
||||
bankAccount = map[string]interface{}{
|
||||
"id": u.BankAccount.ID,
|
||||
"mandate_date_signed": u.BankAccount.MandateDateSigned,
|
||||
"bank": u.BankAccount.Bank,
|
||||
"account_holder_name": u.BankAccount.AccountHolderName,
|
||||
"iban": u.BankAccount.IBAN,
|
||||
"bic": u.BankAccount.BIC,
|
||||
"mandate_reference": u.BankAccount.MandateReference,
|
||||
}
|
||||
}
|
||||
result := map[string]interface{}{
|
||||
"email": u.Email,
|
||||
"first_name": u.FirstName,
|
||||
"last_name": u.LastName,
|
||||
"phone": u.Phone,
|
||||
"notes": u.Notes,
|
||||
"address": u.Address,
|
||||
"zip_code": u.ZipCode,
|
||||
"city": u.City,
|
||||
"status": u.Status,
|
||||
"id": u.ID,
|
||||
"role_id": u.RoleID,
|
||||
"company": u.Company,
|
||||
"dateofbirth": u.DateOfBirth,
|
||||
"membership": membership,
|
||||
"licence": licence,
|
||||
"bank_account": bankAccount,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -439,14 +539,12 @@ func extractUserIDFrom(tokenString string) (uint, error) {
|
||||
}
|
||||
|
||||
func GetUsersWhere(db *gorm.DB, where map[string]interface{}) (*[]User, error) {
|
||||
logger.Error.Printf("where: %#v", where)
|
||||
var users []User
|
||||
result := db.
|
||||
Preload(clause.Associations).
|
||||
Preload("Membership").
|
||||
Preload("Membership.SubscriptionModel").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
Preload("Verifications").
|
||||
Where(where).Find(&users)
|
||||
if result.Error != nil {
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
|
||||
@@ -1,15 +1,48 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Verification struct {
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
gorm.Model
|
||||
VerifiedAt *time.Time `json:"verified_at"`
|
||||
VerificationToken string `json:"token"`
|
||||
ID uint `gorm:"primaryKey"`
|
||||
UserID uint `json:"user_id"`
|
||||
Type string
|
||||
}
|
||||
|
||||
func (v *Verification) Create(db *gorm.DB) error {
|
||||
if err := db.Create(v).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info.Printf("verification created: %#v", v)
|
||||
// Preload all associations to return the fully populated object
|
||||
return db.First(v, v.ID).Error // Refresh the verification object with all associations
|
||||
}
|
||||
|
||||
func (v *Verification) Update(db *gorm.DB) error {
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingVerification Verification
|
||||
|
||||
logger.Info.Printf("updating verification: %#v", v)
|
||||
if err := tx.First(&existingVerification, v.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&existingVerification).Updates(v).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.First(v, v.ID).Error
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (v *Verification) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&v).Error
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func GetUsersBySubscription(subscriptionID uint) (*[]models.User, error) {
|
||||
Preload("BankAccount").
|
||||
Preload("Licence").
|
||||
Preload("Licence.Categories").
|
||||
Joins("JOIN memberships ON users.membership_id = memberships.id").
|
||||
Joins("JOIN memberships ON users.id = memberships.user_id").
|
||||
Joins("JOIN subscription_models ON memberships.subscription_model_id = subscription_models.id").
|
||||
Where("subscription_models.id = ?", subscriptionID).
|
||||
Find(&users).Error
|
||||
|
||||
@@ -68,14 +68,11 @@ func (s *UserService) Update(user *models.User) (*models.User, error) {
|
||||
if err := existingUser.FromID(s.DB, &user.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.MembershipID = existingUser.MembershipID
|
||||
user.Membership.ID = existingUser.Membership.ID
|
||||
if existingUser.Licence != nil {
|
||||
user.Licence.ID = existingUser.Licence.ID
|
||||
user.LicenceID = existingUser.LicenceID
|
||||
}
|
||||
user.BankAccount.ID = existingUser.BankAccount.ID
|
||||
user.BankAccountID = existingUser.BankAccountID
|
||||
|
||||
user.SetPassword(user.Password)
|
||||
|
||||
@@ -109,7 +106,6 @@ func (s *UserService) Register(user *models.User) (id uint, token string, err er
|
||||
user.Membership.SubscriptionModel = *selectedModel
|
||||
user.Membership.SubscriptionModelID = selectedModel.ID
|
||||
user.Status = constants.UnverifiedStatus
|
||||
user.PaymentStatus = constants.AwaitingPaymentStatus
|
||||
user.BankAccount.MandateDateSigned = time.Now()
|
||||
v, err := user.SetVerification(constants.VerificationTypes.Email)
|
||||
if err != nil {
|
||||
|
||||
@@ -10,7 +10,7 @@ type User struct {
|
||||
Age int
|
||||
Address *Address
|
||||
Tags []string
|
||||
License License
|
||||
Licence Licence
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
@@ -18,7 +18,7 @@ type Address struct {
|
||||
Country string
|
||||
}
|
||||
|
||||
type License struct {
|
||||
type Licence struct {
|
||||
ID string
|
||||
Categories []string
|
||||
}
|
||||
@@ -98,22 +98,22 @@ func TestFilterAllowedStructFields(t *testing.T) {
|
||||
{
|
||||
name: "Filter slice of structs",
|
||||
input: &User{
|
||||
License: License{
|
||||
Licence: Licence{
|
||||
ID: "123",
|
||||
Categories: []string{"A", "B"},
|
||||
},
|
||||
},
|
||||
existing: &User{
|
||||
License: License{
|
||||
Licence: Licence{
|
||||
ID: "456",
|
||||
Categories: []string{"C"},
|
||||
},
|
||||
},
|
||||
allowedFields: map[string]bool{
|
||||
"License.ID": true,
|
||||
"Licence.ID": true,
|
||||
},
|
||||
expectedResult: &User{
|
||||
License: License{
|
||||
Licence: Licence{
|
||||
ID: "123", // Allowed field
|
||||
Categories: []string{"C"}, // Kept from existing
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user