refactoring

This commit is contained in:
Alex
2025-03-24 17:45:33 +01:00
parent 741145b960
commit 28dfe7ecde
11 changed files with 528 additions and 155 deletions

View File

@@ -1,15 +1,50 @@
package models package models
import "time" import (
"GoMembership/pkg/logger"
"time"
"gorm.io/gorm"
)
type BankAccount struct { type BankAccount struct {
ID uint `gorm:"primaryKey"` ID uint `gorm:"primaryKey"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt 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"` Bank string `json:"bank_name" binding:"safe_content"`
AccountHolderName string `json:"account_holder_name" binding:"safe_content"` AccountHolderName string `json:"account_holder_name" binding:"safe_content"`
IBAN string `json:"iban" binding:"safe_content"` IBAN string `json:"iban" binding:"safe_content"`
BIC string `json:"bic" 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
} }

View 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
}

View File

@@ -1,17 +1,55 @@
package models package models
import ( import (
"GoMembership/pkg/logger"
"strings"
"time" "time"
"gorm.io/gorm"
) )
type Consent struct { type Consent struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
FirstName string `gorm:"not null" json:"first_name" binding:"safe_content"` FirstName string `gorm:"not null" json:"first_name" binding:"safe_content"`
LastName string `gorm:"not null" json:"last_name" binding:"safe_content"` LastName string `gorm:"not null" json:"last_name" binding:"safe_content"`
Email string `json:"email" binding:"email,safe_content"` Email string `json:"email" binding:"email,safe_content"`
ConsentType string `gorm:"not null" json:"consent_type" binding:"safe_content"` ConsentType string `gorm:"not null" json:"consent_type" binding:"safe_content"`
ID uint `gorm:"primaryKey"` UserID uint `gorm:"not null" json:"user_id"`
User User }
UserID uint
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
} }

View File

@@ -1,7 +1,11 @@
package models package models
import ( import (
"GoMembership/pkg/logger"
"fmt"
"time" "time"
"gorm.io/gorm"
) )
type Licence struct { type Licence struct {
@@ -14,10 +18,49 @@ type Licence struct {
IssuedDate time.Time `json:"issued_date" binding:"omitempty"` IssuedDate time.Time `json:"issued_date" binding:"omitempty"`
ExpirationDate time.Time `json:"expiration_date" binding:"omitempty"` ExpirationDate time.Time `json:"expiration_date" binding:"omitempty"`
IssuingCountry string `json:"country" binding:"safe_content"` 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 { func (l *Licence) BeforeSafe(tx *gorm.DB) error {
ID uint `json:"id" gorm:"primaryKey"` if err := tx.Model(l).Association("Categories").Replace(l.Categories); err != nil {
Name string `json:"category" binding:"safe_content"` 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
} }

View File

@@ -1,8 +1,15 @@
package models package models
import "time" import (
"GoMembership/pkg/logger"
"time"
"gorm.io/gorm"
)
type Membership struct { type Membership struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"index" json:"user_id"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
StartDate time.Time `json:"start_date"` StartDate time.Time `json:"start_date"`
@@ -11,5 +18,41 @@ type Membership struct {
SubscriptionModel SubscriptionModel `gorm:"foreignKey:SubscriptionModelID" json:"subscription_model"` SubscriptionModel SubscriptionModel `gorm:"foreignKey:SubscriptionModelID" json:"subscription_model"`
SubscriptionModelID uint `json:"subsription_model_id"` SubscriptionModelID uint `json:"subsription_model_id"`
ParentMembershipID uint `json:"parent_member_id" binding:"omitempty,omitnil,number"` 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
} }

View File

@@ -1,7 +1,10 @@
package models package models
import ( import (
"GoMembership/pkg/logger"
"time" "time"
"gorm.io/gorm"
) )
type SubscriptionModel struct { type SubscriptionModel struct {
@@ -17,3 +20,39 @@ type SubscriptionModel struct {
IncludedPerYear int16 `json:"included_hours_per_year"` IncludedPerYear int16 `json:"included_hours_per_year"`
IncludedPerMonth int16 `json:"included_hours_per_month"` 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
}

View File

@@ -8,6 +8,7 @@ import (
"GoMembership/pkg/logger" "GoMembership/pkg/logger"
"fmt" "fmt"
"slices" "slices"
"strings"
"time" "time"
"github.com/alexedwards/argon2id" "github.com/alexedwards/argon2id"
@@ -18,7 +19,7 @@ import (
) )
type User struct { type User struct {
ID uint `gorm:"primarykey" json:"id"` ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
DeletedAt *time.Time DeletedAt *time.Time
@@ -30,32 +31,31 @@ type User struct {
Password string `json:"password" binding:"safe_content"` Password string `json:"password" binding:"safe_content"`
Email string `gorm:"uniqueIndex:idx_users_email,not null" json:"email" binding:"required,email,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"` 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"` Address string `gorm:"not null" json:"address" binding:"required,safe_content"`
ZipCode string `gorm:"not null" json:"zip_code" binding:"required,alphanum,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"` City string `form:"not null" json:"city" binding:"required,alphaunicode,safe_content"`
Consents []Consent `gorm:"constraint:OnUpdate:CASCADE"` Consents []Consent `gorm:"constraint:OnUpdate:CASCADE"`
BankAccount BankAccount `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"bank_account"` BankAccount *BankAccount `gorm:"foreignkey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"bank_account"`
BankAccountID uint Verifications []Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
Verifications *[]Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Membership *Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"membership"`
Membership Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"membership"`
MembershipID uint
Licence *Licence `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"licence"` Licence *Licence `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"licence"`
LicenceID uint
PaymentStatus int8 `json:"payment_status"`
Status int8 `json:"status"` Status int8 `json:"status"`
RoleID int8 `json:"role_id"` RoleID int8 `json:"role_id"`
} }
func (u *User) AfterCreate(tx *gorm.DB) (err error) { func (u *User) AfterCreate(tx *gorm.DB) (err error) {
if u.BankAccount.ID != 0 && u.BankAccount.MandateReference == "" { if u.BankAccount != nil && u.BankAccount.MandateReference == "" {
mandateReference := u.GenerateMandateReference() u.BankAccount.MandateReference = u.GenerateMandateReference()
u.BankAccount.Update(tx)
return tx.Model(&u.BankAccount).Update("MandateReference", mandateReference).Error
} }
return nil return nil
} }
func (u *User) BeforeSave(tx *gorm.DB) (err error) {
u.Email = strings.ToLower(u.Email)
return nil
}
func (u *User) GenerateMandateReference() string { func (u *User) GenerateMandateReference() string {
return fmt.Sprintf("%s%d%s", time.Now().Format("20060102"), u.ID, u.BankAccount.IBAN) 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 { func (u *User) Create(db *gorm.DB) error {
return db.Transaction(func(tx *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.Preload(clause.Associations).Create(u).Error; err != nil {
if err := tx.Create(u).Error; err != nil {
return err return err
} }
// Replace associated Categories (assumes Categories already exist) return nil
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 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 { func (u *User) Update(db *gorm.DB) error {
err := db.Transaction(func(tx *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) logger.Info.Printf("updating user: %#v", u)
if err := tx. if err := tx.
Preload("Membership").
Preload("Membership.SubscriptionModel").
Preload("Licence").
Preload("Licence.Categories").
Preload("Verifications").
First(&existingUser, u.ID).Error; err != nil { First(&existingUser, u.ID).Error; err != nil {
return err return err
} }
// Update the user's main fields // 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 { if result.Error != nil {
logger.Error.Printf("User update error in update user: %#v", result.Error) logger.Error.Printf("User update error in update user: %#v", result.Error)
return result.Error return result.Error
@@ -143,28 +237,28 @@ func (u *User) Update(db *gorm.DB) error {
} }
} }
// Update the Membership if provided // // Update the Membership if provided
if u.Membership.ID != 0 { // if u.Membership.ID != 0 {
if err := tx.Model(&existingUser.Membership).Updates(u.Membership).Error; err != nil { // 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) // logger.Error.Printf("Membership update error in update user: %#v", err)
return err // return err
} // }
} // }
if u.Licence != nil { // if u.Licence != nil {
u.Licence.UserID = existingUser.ID // u.Licence.UserID = existingUser.ID
if err := tx.Save(u.Licence).Error; err != nil { // if err := tx.Save(u.Licence).Error; err != nil {
return err // return err
} // }
if err := tx.Model(&existingUser).Update("LicenceID", u.Licence.ID).Error; err != nil { // if err := tx.Model(&existingUser).Update("LicenceID", u.Licence.ID).Error; err != nil {
return err // return err
} // }
if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil { // if err := tx.Model(u.Licence).Association("Categories").Replace(u.Licence.Categories); err != nil {
return err // return err
} // }
} // }
// if u.Licence != nil { // if u.Licence != nil {
// if existingUser.Licence == nil || existingUser.LicenceID == 0 { // if existingUser.Licence == nil || existingUser.LicenceID == 0 {
// u.Licence.UserID = existingUser.ID // Ensure Licence belongs to User // 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 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 return err
} }
} }
@@ -199,11 +299,9 @@ func (u *User) Update(db *gorm.DB) error {
} }
return db. return db.
Preload("Membership"). Preload(clause.Associations).
Preload("Membership.SubscriptionModel"). Preload("Membership.SubscriptionModel").
Preload("Licence").
Preload("Licence.Categories"). Preload("Licence.Categories").
Preload("Verifications").
First(&u, u.ID).Error First(&u, u.ID).Error
} }
@@ -211,11 +309,8 @@ func (u *User) FromID(db *gorm.DB, userID *uint) error {
var user User var user User
result := db. result := db.
Preload(clause.Associations). Preload(clause.Associations).
Preload("Membership").
Preload("Membership.SubscriptionModel"). Preload("Membership.SubscriptionModel").
Preload("Licence").
Preload("Licence.Categories"). Preload("Licence.Categories").
Preload("Verifications").
First(&user, userID) First(&user, userID)
if result.Error != nil { if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound { if result.Error == gorm.ErrRecordNotFound {
@@ -231,11 +326,8 @@ func (u *User) FromEmail(db *gorm.DB, email *string) error {
var user User var user User
result := db. result := db.
Preload(clause.Associations). Preload(clause.Associations).
Preload("Membership").
Preload("Membership.SubscriptionModel"). Preload("Membership.SubscriptionModel").
Preload("Licence").
Preload("Licence.Categories"). Preload("Licence.Categories").
Preload("Verifications").
Where("email = ?", email).First(&user) Where("email = ?", email).First(&user)
if result.Error != nil { if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound { if result.Error == gorm.ErrRecordNotFound {
@@ -284,7 +376,7 @@ func (u *User) IsSupporter() bool {
func (u *User) SetVerification(verificationType string) (*Verification, error) { func (u *User) SetVerification(verificationType string) (*Verification, error) {
if u.Verifications == nil { if u.Verifications == nil {
u.Verifications = new([]Verification) u.Verifications = []Verification{}
} }
token, err := utils.GenerateVerificationToken() token, err := utils.GenerateVerificationToken()
if err != nil { if err != nil {
@@ -295,10 +387,10 @@ func (u *User) SetVerification(verificationType string) (*Verification, error) {
VerificationToken: token, VerificationToken: token,
Type: verificationType, Type: verificationType,
} }
if vi := slices.IndexFunc(*u.Verifications, func(vsl Verification) bool { return vsl.Type == v.Type }); vi > -1 { if vi := slices.IndexFunc(u.Verifications, func(vsl Verification) bool { return vsl.Type == v.Type }); vi > -1 {
(*u.Verifications)[vi] = v u.Verifications[vi] = v
} else { } else {
*u.Verifications = append(*u.Verifications, v) u.Verifications = append(u.Verifications, v)
} }
return &v, nil return &v, nil
} }
@@ -307,11 +399,11 @@ func (u *User) GetVerification(verificationType string) (*Verification, error) {
if u.Verifications == nil { if u.Verifications == nil {
return nil, errors.ErrNoData 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 { if vi == -1 {
return nil, errors.ErrNotFound return nil, errors.ErrNotFound
} }
return &(*u.Verifications)[vi], nil return &u.Verifications[vi], nil
} }
func (u *User) Verify(token string, verificationType string) bool { func (u *User) Verify(token string, verificationType string) bool {
@@ -320,7 +412,7 @@ func (u *User) Verify(token string, verificationType string) bool {
return false 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 return vsl.Type == verificationType && vsl.VerificationToken == token
}) })
@@ -329,32 +421,22 @@ func (u *User) Verify(token string, verificationType string) bool {
return false return false
} }
if (*u.Verifications)[vi].VerifiedAt != nil { if u.Verifications[vi].VerifiedAt != nil {
logger.Error.Printf("VerifiedAt is not nil, already verified?: %#v", (*u.Verifications)[vi]) logger.Error.Printf("VerifiedAt is not nil, already verified?: %#v", u.Verifications[vi])
return false return false
} }
t := time.Now() t := time.Now()
(*u.Verifications)[vi].VerifiedAt = &t u.Verifications[vi].VerifiedAt = &t
return true return true
} }
func (u *User) Safe() map[string]interface{} { func (u *User) Safe() map[string]interface{} {
result := map[string]interface{}{ var membership map[string]interface{} = nil
"email": u.Email, var licence map[string]interface{} = nil
"first_name": u.FirstName, var bankAccount map[string]interface{} = nil
"last_name": u.LastName, if u.Membership != nil {
"phone": u.Phone, membership = map[string]interface{}{
"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{}{
"id": u.Membership.ID, "id": u.Membership.ID,
"start_date": u.Membership.StartDate, "start_date": u.Membership.StartDate,
"end_date": u.Membership.EndDate, "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_year": u.Membership.SubscriptionModel.IncludedPerYear,
"included_per_month": u.Membership.SubscriptionModel.IncludedPerMonth, "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 { if u.Licence != nil {
result["licence"] = map[string]interface{}{ licence = map[string]interface{}{
"id": u.Licence.ID, "id": u.Licence.ID,
"number": u.Licence.Number, "number": u.Licence.Number,
"status": u.Licence.Status, "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 return result
} }
@@ -439,14 +539,12 @@ func extractUserIDFrom(tokenString string) (uint, error) {
} }
func GetUsersWhere(db *gorm.DB, where map[string]interface{}) (*[]User, error) { func GetUsersWhere(db *gorm.DB, where map[string]interface{}) (*[]User, error) {
logger.Error.Printf("where: %#v", where)
var users []User var users []User
result := db. result := db.
Preload(clause.Associations). Preload(clause.Associations).
Preload("Membership").
Preload("Membership.SubscriptionModel"). Preload("Membership.SubscriptionModel").
Preload("Licence").
Preload("Licence.Categories"). Preload("Licence.Categories").
Preload("Verifications").
Where(where).Find(&users) Where(where).Find(&users)
if result.Error != nil { if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound { if result.Error == gorm.ErrRecordNotFound {

View File

@@ -1,15 +1,48 @@
package models package models
import ( import (
"GoMembership/pkg/logger"
"time" "time"
"gorm.io/gorm"
) )
type Verification struct { type Verification struct {
UpdatedAt time.Time gorm.Model
CreatedAt time.Time
VerifiedAt *time.Time `json:"verified_at"` VerifiedAt *time.Time `json:"verified_at"`
VerificationToken string `json:"token"` VerificationToken string `json:"token"`
ID uint `gorm:"primaryKey"`
UserID uint `json:"user_id"` UserID uint `json:"user_id"`
Type string 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
}

View File

@@ -83,7 +83,7 @@ func GetUsersBySubscription(subscriptionID uint) (*[]models.User, error) {
Preload("BankAccount"). Preload("BankAccount").
Preload("Licence"). Preload("Licence").
Preload("Licence.Categories"). 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"). Joins("JOIN subscription_models ON memberships.subscription_model_id = subscription_models.id").
Where("subscription_models.id = ?", subscriptionID). Where("subscription_models.id = ?", subscriptionID).
Find(&users).Error Find(&users).Error

View File

@@ -68,14 +68,11 @@ func (s *UserService) Update(user *models.User) (*models.User, error) {
if err := existingUser.FromID(s.DB, &user.ID); err != nil { if err := existingUser.FromID(s.DB, &user.ID); err != nil {
return nil, err return nil, err
} }
user.MembershipID = existingUser.MembershipID
user.Membership.ID = existingUser.Membership.ID user.Membership.ID = existingUser.Membership.ID
if existingUser.Licence != nil { if existingUser.Licence != nil {
user.Licence.ID = existingUser.Licence.ID user.Licence.ID = existingUser.Licence.ID
user.LicenceID = existingUser.LicenceID
} }
user.BankAccount.ID = existingUser.BankAccount.ID user.BankAccount.ID = existingUser.BankAccount.ID
user.BankAccountID = existingUser.BankAccountID
user.SetPassword(user.Password) 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.SubscriptionModel = *selectedModel
user.Membership.SubscriptionModelID = selectedModel.ID user.Membership.SubscriptionModelID = selectedModel.ID
user.Status = constants.UnverifiedStatus user.Status = constants.UnverifiedStatus
user.PaymentStatus = constants.AwaitingPaymentStatus
user.BankAccount.MandateDateSigned = time.Now() user.BankAccount.MandateDateSigned = time.Now()
v, err := user.SetVerification(constants.VerificationTypes.Email) v, err := user.SetVerification(constants.VerificationTypes.Email)
if err != nil { if err != nil {

View File

@@ -10,7 +10,7 @@ type User struct {
Age int Age int
Address *Address Address *Address
Tags []string Tags []string
License License Licence Licence
} }
type Address struct { type Address struct {
@@ -18,7 +18,7 @@ type Address struct {
Country string Country string
} }
type License struct { type Licence struct {
ID string ID string
Categories []string Categories []string
} }
@@ -98,22 +98,22 @@ func TestFilterAllowedStructFields(t *testing.T) {
{ {
name: "Filter slice of structs", name: "Filter slice of structs",
input: &User{ input: &User{
License: License{ Licence: Licence{
ID: "123", ID: "123",
Categories: []string{"A", "B"}, Categories: []string{"A", "B"},
}, },
}, },
existing: &User{ existing: &User{
License: License{ Licence: Licence{
ID: "456", ID: "456",
Categories: []string{"C"}, Categories: []string{"C"},
}, },
}, },
allowedFields: map[string]bool{ allowedFields: map[string]bool{
"License.ID": true, "Licence.ID": true,
}, },
expectedResult: &User{ expectedResult: &User{
License: License{ Licence: Licence{
ID: "123", // Allowed field ID: "123", // Allowed field
Categories: []string{"C"}, // Kept from existing Categories: []string{"C"}, // Kept from existing
}, },