init push
This commit is contained in:
286
internal/repository/mysql/user_roles.go
Normal file
286
internal/repository/mysql/user_roles.go
Normal file
@@ -0,0 +1,286 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"wucher/internal/domain/auth"
|
||||
"wucher/internal/domain/user"
|
||||
)
|
||||
|
||||
type userRoleJoinRow struct {
|
||||
UserID []byte `gorm:"column:user_id"`
|
||||
RoleID []byte `gorm:"column:role_id"`
|
||||
RoleName string `gorm:"column:role_name"`
|
||||
RoleDescription string `gorm:"column:role_description"`
|
||||
}
|
||||
|
||||
func normalizeAssignedRoleIDs(primaryRoleID []byte, roleIDs [][]byte) [][]byte {
|
||||
out := make([][]byte, 0, len(roleIDs)+1)
|
||||
seen := make(map[string]struct{}, len(roleIDs)+1)
|
||||
|
||||
appendRole := func(roleID []byte) {
|
||||
if len(roleID) != 16 {
|
||||
return
|
||||
}
|
||||
key := string(roleID)
|
||||
if _, exists := seen[key]; exists {
|
||||
return
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
out = append(out, append([]byte(nil), roleID...))
|
||||
}
|
||||
|
||||
appendRole(primaryRoleID)
|
||||
for i := range roleIDs {
|
||||
appendRole(roleIDs[i])
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func replaceUserRolesTx(ctx context.Context, tx *gorm.DB, userID, primaryRoleID []byte, roleIDs [][]byte) error {
|
||||
normalized := normalizeAssignedRoleIDs(primaryRoleID, roleIDs)
|
||||
if len(userID) != 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := tx.Where("user_id = ?", userID).Delete(&auth.UserRole{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(normalized) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
actor := actorUserIDFromContext(ctx)
|
||||
items := make([]auth.UserRole, 0, len(normalized))
|
||||
for i := range normalized {
|
||||
item := auth.UserRole{
|
||||
UserID: userID,
|
||||
RoleID: normalized[i],
|
||||
}
|
||||
if len(actor) > 0 {
|
||||
item.CreatedBy = actor
|
||||
item.UpdatedBy = actor
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return tx.Create(&items).Error
|
||||
}
|
||||
|
||||
func listUserRoleIDsTx(tx *gorm.DB, userID []byte) ([][]byte, error) {
|
||||
var rows []struct {
|
||||
RoleID []byte `gorm:"column:role_id"`
|
||||
}
|
||||
if err := tx.Table("user_roles").
|
||||
Select("role_id").
|
||||
Where("user_id = ?", userID).
|
||||
Find(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roleIDs := make([][]byte, 0, len(rows))
|
||||
for i := range rows {
|
||||
if len(rows[i].RoleID) != 16 {
|
||||
continue
|
||||
}
|
||||
roleIDs = append(roleIDs, append([]byte(nil), rows[i].RoleID...))
|
||||
}
|
||||
return roleIDs, nil
|
||||
}
|
||||
|
||||
func replacePrimaryUserRoleTx(ctx context.Context, tx *gorm.DB, userID, currentPrimaryRoleID, newPrimaryRoleID []byte) error {
|
||||
roleIDs, err := listUserRoleIDsTx(tx, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filtered := make([][]byte, 0, len(roleIDs))
|
||||
currentPrimaryKey := string(currentPrimaryRoleID)
|
||||
newPrimaryKey := string(newPrimaryRoleID)
|
||||
for i := range roleIDs {
|
||||
key := string(roleIDs[i])
|
||||
if key == currentPrimaryKey || key == newPrimaryKey {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, roleIDs[i])
|
||||
}
|
||||
|
||||
return replaceUserRolesTx(ctx, tx, userID, newPrimaryRoleID, filtered)
|
||||
}
|
||||
|
||||
func loadUserRoleRows(ctx context.Context, db *gorm.DB, userIDs [][]byte) (map[string][]userRoleJoinRow, error) {
|
||||
rowsByUserID := make(map[string][]userRoleJoinRow, len(userIDs))
|
||||
if len(userIDs) == 0 {
|
||||
return rowsByUserID, nil
|
||||
}
|
||||
|
||||
var rows []userRoleJoinRow
|
||||
if err := db.WithContext(ctx).
|
||||
Table("user_roles ur").
|
||||
Select("ur.user_id, roles.id AS role_id, roles.name AS role_name, roles.description AS role_description").
|
||||
Joins("JOIN roles ON roles.id = ur.role_id").
|
||||
Where("ur.user_id IN ?", userIDs).
|
||||
Order("roles.name ASC").
|
||||
Find(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
key := string(rows[i].UserID)
|
||||
rowsByUserID[key] = append(rowsByUserID[key], userRoleJoinRow{
|
||||
UserID: append([]byte(nil), rows[i].UserID...),
|
||||
RoleID: append([]byte(nil), rows[i].RoleID...),
|
||||
RoleName: rows[i].RoleName,
|
||||
RoleDescription: rows[i].RoleDescription,
|
||||
})
|
||||
}
|
||||
|
||||
return rowsByUserID, nil
|
||||
}
|
||||
|
||||
func orderUserRoleRows(primaryRoleID []byte, rows []userRoleJoinRow) []userRoleJoinRow {
|
||||
if len(rows) < 2 || len(primaryRoleID) != 16 {
|
||||
return rows
|
||||
}
|
||||
|
||||
primaryKey := string(primaryRoleID)
|
||||
ordered := make([]userRoleJoinRow, 0, len(rows))
|
||||
for i := range rows {
|
||||
if string(rows[i].RoleID) == primaryKey {
|
||||
ordered = append(ordered, rows[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
for i := range rows {
|
||||
if string(rows[i].RoleID) == primaryKey {
|
||||
continue
|
||||
}
|
||||
ordered = append(ordered, rows[i])
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
|
||||
func loadRoleRowsByID(ctx context.Context, db *gorm.DB, roleIDs [][]byte) (map[string]userRoleJoinRow, error) {
|
||||
out := make(map[string]userRoleJoinRow, len(roleIDs))
|
||||
if len(roleIDs) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
var rows []struct {
|
||||
ID []byte `gorm:"column:id"`
|
||||
Name string `gorm:"column:name"`
|
||||
Description string `gorm:"column:description"`
|
||||
}
|
||||
if err := db.WithContext(ctx).
|
||||
Table("roles").
|
||||
Select("id, name, description").
|
||||
Where("id IN ?", roleIDs).
|
||||
Find(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
out[string(rows[i].ID)] = userRoleJoinRow{
|
||||
RoleID: append([]byte(nil), rows[i].ID...),
|
||||
RoleName: rows[i].Name,
|
||||
RoleDescription: rows[i].Description,
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func attachAuthUserRoles(ctx context.Context, db *gorm.DB, users ...*auth.User) error {
|
||||
userIDs := make([][]byte, 0, len(users))
|
||||
missingPrimaryRoleIDs := make([][]byte, 0, len(users))
|
||||
for i := range users {
|
||||
if users[i] == nil || len(users[i].ID) != 16 {
|
||||
continue
|
||||
}
|
||||
userIDs = append(userIDs, users[i].ID)
|
||||
if len(users[i].RoleID) == 16 {
|
||||
missingPrimaryRoleIDs = append(missingPrimaryRoleIDs, users[i].RoleID)
|
||||
}
|
||||
}
|
||||
|
||||
rowsByUserID, err := loadUserRoleRows(ctx, db, userIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
roleRowsByID, err := loadRoleRowsByID(ctx, db, missingPrimaryRoleIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range users {
|
||||
if users[i] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rows := orderUserRoleRows(users[i].RoleID, rowsByUserID[string(users[i].ID)])
|
||||
if len(rows) == 0 && len(users[i].RoleID) == 16 {
|
||||
if roleRow, ok := roleRowsByID[string(users[i].RoleID)]; ok {
|
||||
rows = []userRoleJoinRow{roleRow}
|
||||
}
|
||||
}
|
||||
|
||||
users[i].RoleIDs = make([][]byte, 0, len(rows))
|
||||
users[i].Roles = make([]auth.Role, 0, len(rows))
|
||||
for j := range rows {
|
||||
users[i].RoleIDs = append(users[i].RoleIDs, append([]byte(nil), rows[j].RoleID...))
|
||||
users[i].Roles = append(users[i].Roles, auth.Role{
|
||||
ID: append([]byte(nil), rows[j].RoleID...),
|
||||
Name: rows[j].RoleName,
|
||||
Description: rows[j].RoleDescription,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func attachUserDomainRoles(ctx context.Context, db *gorm.DB, users ...*user.User) error {
|
||||
userIDs := make([][]byte, 0, len(users))
|
||||
for i := range users {
|
||||
if users[i] == nil || len(users[i].ID) != 16 {
|
||||
continue
|
||||
}
|
||||
userIDs = append(userIDs, users[i].ID)
|
||||
}
|
||||
|
||||
rowsByUserID, err := loadUserRoleRows(ctx, db, userIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range users {
|
||||
if users[i] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rows := orderUserRoleRows(users[i].RoleID, rowsByUserID[string(users[i].ID)])
|
||||
if len(rows) == 0 && len(users[i].RoleID) == 16 {
|
||||
rows = []userRoleJoinRow{{
|
||||
RoleID: append([]byte(nil), users[i].RoleID...),
|
||||
RoleName: users[i].RoleName,
|
||||
RoleDescription: users[i].RoleDescription,
|
||||
}}
|
||||
}
|
||||
|
||||
users[i].RoleIDs = make([][]byte, 0, len(rows))
|
||||
users[i].Roles = make([]user.RoleSummary, 0, len(rows))
|
||||
for j := range rows {
|
||||
users[i].RoleIDs = append(users[i].RoleIDs, append([]byte(nil), rows[j].RoleID...))
|
||||
users[i].Roles = append(users[i].Roles, user.RoleSummary{
|
||||
ID: append([]byte(nil), rows[j].RoleID...),
|
||||
Name: rows[j].RoleName,
|
||||
Description: rows[j].RoleDescription,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user