package processor import ( "context" "time" "eslogad-be/internal/entities" "github.com/google/uuid" "gorm.io/gorm" ) type UserRoleProcessor interface { AssignRoleToUser(ctx context.Context, userID, roleID uuid.UUID) error RemoveRoleFromUser(ctx context.Context, userID, roleID uuid.UUID) error GetUserRoles(ctx context.Context, userID uuid.UUID) ([]entities.Role, error) HasRole(ctx context.Context, userID uuid.UUID, roleCode string) (bool, error) } type UserRoleProcessorImpl struct { db *gorm.DB } func NewUserRoleProcessor(db *gorm.DB) *UserRoleProcessorImpl { return &UserRoleProcessorImpl{ db: db, } } type UserRoleEntry struct { ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"` UserID uuid.UUID `gorm:"type:uuid;not null"` RoleID uuid.UUID `gorm:"type:uuid;not null"` AssignedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` RemovedAt *time.Time } func (UserRoleEntry) TableName() string { return "user_role" } func (p *UserRoleProcessorImpl) AssignRoleToUser(ctx context.Context, userID, roleID uuid.UUID) error { var existingEntry UserRoleEntry err := p.db.WithContext(ctx). Where("user_id = ? AND role_id = ? AND removed_at IS NULL", userID, roleID). First(&existingEntry).Error if err == nil { return nil } if err != gorm.ErrRecordNotFound { return err } newEntry := UserRoleEntry{ UserID: userID, RoleID: roleID, AssignedAt: time.Now(), } return p.db.WithContext(ctx).Create(&newEntry).Error } func (p *UserRoleProcessorImpl) RemoveRoleFromUser(ctx context.Context, userID, roleID uuid.UUID) error { now := time.Now() return p.db.WithContext(ctx). Model(&UserRoleEntry{}). Where("user_id = ? AND role_id = ? AND removed_at IS NULL", userID, roleID). Update("removed_at", now).Error } func (p *UserRoleProcessorImpl) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]entities.Role, error) { var roles []entities.Role err := p.db.WithContext(ctx). Table("roles as r"). Select("r.*"). Joins("JOIN user_role ur ON ur.role_id = r.id AND ur.removed_at IS NULL"). Where("ur.user_id = ?", userID). Find(&roles).Error return roles, err } func (p *UserRoleProcessorImpl) HasRole(ctx context.Context, userID uuid.UUID, roleCode string) (bool, error) { var count int64 err := p.db.WithContext(ctx). Table("user_role as ur"). Joins("JOIN roles r ON r.id = ur.role_id"). Where("ur.user_id = ? AND r.code = ? AND ur.removed_at IS NULL", userID, roleCode). Count(&count).Error if err != nil { return false, err } return count > 0, nil }