feat: complete superadmin management endpoints

This commit is contained in:
2026-01-09 09:52:23 +08:00
parent 3e095c57f3
commit c0cebb6fb9
6 changed files with 877 additions and 33 deletions

View File

@@ -88,8 +88,118 @@ func (s *super) CheckToken(ctx context.Context, token string) (*super_dto.LoginR
func (s *super) ListUsers(ctx context.Context, filter *super_dto.UserListFilter) (*requests.Pager, error) {
tbl, q := models.UserQuery.QueryContext(ctx)
if filter.Username != nil && *filter.Username != "" {
q = q.Where(tbl.Username.Like("%" + *filter.Username + "%")).Or(tbl.Nickname.Like("%" + *filter.Username + "%"))
if filter.ID != nil && *filter.ID > 0 {
q = q.Where(tbl.ID.Eq(*filter.ID))
}
if filter.Username != nil && strings.TrimSpace(*filter.Username) != "" {
keyword := "%" + strings.TrimSpace(*filter.Username) + "%"
q = q.Where(tbl.Username.Like(keyword)).Or(tbl.Nickname.Like(keyword))
}
if filter.Status != nil && *filter.Status != "" {
q = q.Where(tbl.Status.Eq(*filter.Status))
}
if filter.Role != nil && *filter.Role != "" {
q = q.Where(tbl.Roles.Contains(types.Array[consts.Role]{*filter.Role}))
}
if filter.TenantID != nil && *filter.TenantID > 0 {
// 按租户成员过滤用户,需要先定位租户成员关系。
tblTu, qTu := models.TenantUserQuery.QueryContext(ctx)
userIDs, err := qTu.Where(tblTu.TenantID.Eq(*filter.TenantID)).Select(tblTu.UserID).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
ids := make([]int64, 0, len(userIDs))
for _, row := range userIDs {
ids = append(ids, row.UserID)
}
if len(ids) == 0 {
q = q.Where(tbl.ID.Eq(-1))
} else {
q = q.Where(tbl.ID.In(ids...))
}
}
if filter.CreatedAtFrom != nil {
from, err := s.parseFilterTime(filter.CreatedAtFrom)
if err != nil {
return nil, err
}
if from != nil {
q = q.Where(tbl.CreatedAt.Gte(*from))
}
}
if filter.CreatedAtTo != nil {
to, err := s.parseFilterTime(filter.CreatedAtTo)
if err != nil {
return nil, err
}
if to != nil {
q = q.Where(tbl.CreatedAt.Lte(*to))
}
}
if filter.VerifiedAtFrom != nil {
from, err := s.parseFilterTime(filter.VerifiedAtFrom)
if err != nil {
return nil, err
}
if from != nil {
q = q.Where(tbl.VerifiedAt.Gte(*from))
}
}
if filter.VerifiedAtTo != nil {
to, err := s.parseFilterTime(filter.VerifiedAtTo)
if err != nil {
return nil, err
}
if to != nil {
q = q.Where(tbl.VerifiedAt.Lte(*to))
}
}
orderApplied := false
if filter.Desc != nil && strings.TrimSpace(*filter.Desc) != "" {
switch strings.TrimSpace(*filter.Desc) {
case "id":
q = q.Order(tbl.ID.Desc())
case "username":
q = q.Order(tbl.Username.Desc())
case "status":
q = q.Order(tbl.Status.Desc())
case "verified_at":
q = q.Order(tbl.VerifiedAt.Desc())
case "created_at":
q = q.Order(tbl.CreatedAt.Desc())
case "updated_at":
q = q.Order(tbl.UpdatedAt.Desc())
case "balance":
q = q.Order(tbl.Balance.Desc())
case "balance_frozen":
q = q.Order(tbl.BalanceFrozen.Desc())
}
orderApplied = true
} else if filter.Asc != nil && strings.TrimSpace(*filter.Asc) != "" {
switch strings.TrimSpace(*filter.Asc) {
case "id":
q = q.Order(tbl.ID)
case "username":
q = q.Order(tbl.Username)
case "status":
q = q.Order(tbl.Status)
case "verified_at":
q = q.Order(tbl.VerifiedAt)
case "created_at":
q = q.Order(tbl.CreatedAt)
case "updated_at":
q = q.Order(tbl.UpdatedAt)
case "balance":
q = q.Order(tbl.Balance)
case "balance_frozen":
q = q.Order(tbl.BalanceFrozen)
}
orderApplied = true
}
if !orderApplied {
q = q.Order(tbl.ID.Desc())
}
filter.Pagination.Format()
@@ -103,6 +213,20 @@ func (s *super) ListUsers(ctx context.Context, filter *super_dto.UserListFilter)
return nil, errorx.ErrDatabaseError.WithCause(err)
}
userIDs := make([]int64, 0, len(list))
for _, u := range list {
userIDs = append(userIDs, u.ID)
}
ownedCountMap, err := s.userOwnedTenantCount(ctx, userIDs)
if err != nil {
return nil, err
}
joinedCountMap, err := s.userJoinedTenantCount(ctx, userIDs)
if err != nil {
return nil, err
}
var data []super_dto.UserItem
for _, u := range list {
data = append(data, super_dto.UserItem{
@@ -112,11 +236,14 @@ func (s *super) ListUsers(ctx context.Context, filter *super_dto.UserListFilter)
Roles: u.Roles,
Status: u.Status,
StatusDescription: u.Status.Description(),
CreatedAt: u.CreatedAt.Format(time.RFC3339),
UpdatedAt: u.UpdatedAt.Format(time.RFC3339),
VerifiedAt: s.formatTime(u.VerifiedAt),
CreatedAt: s.formatTime(u.CreatedAt),
UpdatedAt: s.formatTime(u.UpdatedAt),
},
Balance: u.Balance,
BalanceFrozen: u.BalanceFrozen,
Balance: u.Balance,
BalanceFrozen: u.BalanceFrozen,
OwnedTenantCount: ownedCountMap[u.ID],
JoinedTenantCount: joinedCountMap[u.ID],
})
}
@@ -175,8 +302,102 @@ func (s *super) UpdateUserRoles(ctx context.Context, id int64, form *super_dto.U
func (s *super) ListTenants(ctx context.Context, filter *super_dto.TenantListFilter) (*requests.Pager, error) {
tbl, q := models.TenantQuery.QueryContext(ctx)
if filter.Name != nil && *filter.Name != "" {
q = q.Where(tbl.Name.Like("%" + *filter.Name + "%"))
if filter.ID != nil && *filter.ID > 0 {
q = q.Where(tbl.ID.Eq(*filter.ID))
}
if filter.UserID != nil && *filter.UserID > 0 {
q = q.Where(tbl.UserID.Eq(*filter.UserID))
}
if filter.Name != nil && strings.TrimSpace(*filter.Name) != "" {
q = q.Where(tbl.Name.Like("%" + strings.TrimSpace(*filter.Name) + "%"))
}
if filter.Code != nil && strings.TrimSpace(*filter.Code) != "" {
q = q.Where(tbl.Code.Like("%" + strings.TrimSpace(*filter.Code) + "%"))
}
if filter.Status != nil && *filter.Status != "" {
q = q.Where(tbl.Status.Eq(*filter.Status))
}
if filter.ExpiredAtFrom != nil {
from, err := s.parseFilterTime(filter.ExpiredAtFrom)
if err != nil {
return nil, err
}
if from != nil {
q = q.Where(tbl.ExpiredAt.Gte(*from))
}
}
if filter.ExpiredAtTo != nil {
to, err := s.parseFilterTime(filter.ExpiredAtTo)
if err != nil {
return nil, err
}
if to != nil {
q = q.Where(tbl.ExpiredAt.Lte(*to))
}
}
if filter.CreatedAtFrom != nil {
from, err := s.parseFilterTime(filter.CreatedAtFrom)
if err != nil {
return nil, err
}
if from != nil {
q = q.Where(tbl.CreatedAt.Gte(*from))
}
}
if filter.CreatedAtTo != nil {
to, err := s.parseFilterTime(filter.CreatedAtTo)
if err != nil {
return nil, err
}
if to != nil {
q = q.Where(tbl.CreatedAt.Lte(*to))
}
}
orderApplied := false
if filter.Desc != nil && strings.TrimSpace(*filter.Desc) != "" {
switch strings.TrimSpace(*filter.Desc) {
case "id":
q = q.Order(tbl.ID.Desc())
case "name":
q = q.Order(tbl.Name.Desc())
case "code":
q = q.Order(tbl.Code.Desc())
case "status":
q = q.Order(tbl.Status.Desc())
case "expired_at":
q = q.Order(tbl.ExpiredAt.Desc())
case "created_at":
q = q.Order(tbl.CreatedAt.Desc())
case "updated_at":
q = q.Order(tbl.UpdatedAt.Desc())
case "user_id":
q = q.Order(tbl.UserID.Desc())
}
orderApplied = true
} else if filter.Asc != nil && strings.TrimSpace(*filter.Asc) != "" {
switch strings.TrimSpace(*filter.Asc) {
case "id":
q = q.Order(tbl.ID)
case "name":
q = q.Order(tbl.Name)
case "code":
q = q.Order(tbl.Code)
case "status":
q = q.Order(tbl.Status)
case "expired_at":
q = q.Order(tbl.ExpiredAt)
case "created_at":
q = q.Order(tbl.CreatedAt)
case "updated_at":
q = q.Order(tbl.UpdatedAt)
case "user_id":
q = q.Order(tbl.UserID)
}
orderApplied = true
}
if !orderApplied {
q = q.Order(tbl.ID.Desc())
}
filter.Pagination.Format()
@@ -185,24 +406,14 @@ func (s *super) ListTenants(ctx context.Context, filter *super_dto.TenantListFil
return nil, errorx.ErrDatabaseError.WithCause(err)
}
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Order(tbl.ID.Desc()).Find()
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
var data []super_dto.TenantItem
for _, t := range list {
data = append(data, super_dto.TenantItem{
ID: t.ID,
UUID: t.UUID.String(),
Name: t.Name,
Code: t.Code,
Status: t.Status,
StatusDescription: t.Status.Description(),
UserID: t.UserID,
CreatedAt: t.CreatedAt.Format(time.RFC3339),
UpdatedAt: t.UpdatedAt.Format(time.RFC3339),
})
data, err := s.buildTenantItems(ctx, list)
if err != nil {
return nil, err
}
return &requests.Pager{
@@ -240,17 +451,14 @@ func (s *super) GetTenant(ctx context.Context, id int64) (*super_dto.TenantItem,
}
return nil, errorx.ErrDatabaseError.WithCause(err)
}
return &super_dto.TenantItem{
ID: t.ID,
UUID: t.UUID.String(),
Name: t.Name,
Code: t.Code,
Status: t.Status,
StatusDescription: t.Status.Description(),
UserID: t.UserID,
CreatedAt: t.CreatedAt.Format(time.RFC3339),
UpdatedAt: t.UpdatedAt.Format(time.RFC3339),
}, nil
items, err := s.buildTenantItems(ctx, []*models.Tenant{t})
if err != nil {
return nil, err
}
if len(items) == 0 {
return nil, errorx.ErrRecordNotFound
}
return &items[0], nil
}
func (s *super) UpdateTenantStatus(ctx context.Context, id int64, form *super_dto.TenantStatusUpdateForm) error {
@@ -272,6 +480,177 @@ func (s *super) UpdateTenantExpire(ctx context.Context, id int64, form *super_dt
return nil
}
func (s *super) ListTenantUsers(ctx context.Context, tenantID int64, filter *super_dto.SuperTenantUserListFilter) (*requests.Pager, error) {
tbl, q := models.TenantUserQuery.QueryContext(ctx)
q = q.Where(tbl.TenantID.Eq(tenantID))
if filter.UserID != nil && *filter.UserID > 0 {
q = q.Where(tbl.UserID.Eq(*filter.UserID))
}
if filter.Status != nil && *filter.Status != "" {
q = q.Where(tbl.Status.Eq(*filter.Status))
}
if filter.Role != nil && *filter.Role != "" {
q = q.Where(tbl.Role.Contains(types.Array[consts.TenantUserRole]{*filter.Role}))
}
userIDs, userFilter, err := s.lookupUserIDs(ctx, filter.Username)
if err != nil {
return nil, err
}
if userFilter {
if len(userIDs) == 0 {
q = q.Where(tbl.ID.Eq(-1))
} else {
q = q.Where(tbl.UserID.In(userIDs...))
}
}
filter.Pagination.Format()
total, err := q.Count()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Order(tbl.CreatedAt.Desc()).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
userMap, err := s.userMapByTenantUsers(ctx, list)
if err != nil {
return nil, err
}
items := make([]super_dto.SuperTenantUserItem, 0, len(list))
for _, tu := range list {
items = append(items, super_dto.SuperTenantUserItem{
User: s.toSuperUserLite(userMap[tu.UserID]),
TenantUser: s.toSuperTenantUserDTO(tu),
})
}
return &requests.Pager{
Pagination: filter.Pagination,
Total: total,
Items: items,
}, nil
}
func (s *super) ListUserTenants(ctx context.Context, userID int64, filter *super_dto.SuperUserTenantListFilter) (*requests.Pager, error) {
tbl, q := models.TenantUserQuery.QueryContext(ctx)
q = q.Where(tbl.UserID.Eq(userID))
if filter.TenantID != nil && *filter.TenantID > 0 {
q = q.Where(tbl.TenantID.Eq(*filter.TenantID))
}
if filter.Status != nil && *filter.Status != "" {
q = q.Where(tbl.Status.Eq(*filter.Status))
}
if filter.Role != nil && *filter.Role != "" {
q = q.Where(tbl.Role.Contains(types.Array[consts.TenantUserRole]{*filter.Role}))
}
tenantIDs, tenantFilter, err := s.lookupTenantIDs(ctx, filter.Code, filter.Name)
if err != nil {
return nil, err
}
if tenantFilter {
if len(tenantIDs) == 0 {
q = q.Where(tbl.ID.Eq(-1))
} else {
q = q.Where(tbl.TenantID.In(tenantIDs...))
}
}
if filter.CreatedAtFrom != nil {
from, err := s.parseFilterTime(filter.CreatedAtFrom)
if err != nil {
return nil, err
}
if from != nil {
q = q.Where(tbl.CreatedAt.Gte(*from))
}
}
if filter.CreatedAtTo != nil {
to, err := s.parseFilterTime(filter.CreatedAtTo)
if err != nil {
return nil, err
}
if to != nil {
q = q.Where(tbl.CreatedAt.Lte(*to))
}
}
orderApplied := false
if filter.Desc != nil && strings.TrimSpace(*filter.Desc) != "" {
switch strings.TrimSpace(*filter.Desc) {
case "tenant_id":
q = q.Order(tbl.TenantID.Desc())
case "created_at":
q = q.Order(tbl.CreatedAt.Desc())
}
orderApplied = true
} else if filter.Asc != nil && strings.TrimSpace(*filter.Asc) != "" {
switch strings.TrimSpace(*filter.Asc) {
case "tenant_id":
q = q.Order(tbl.TenantID)
case "created_at":
q = q.Order(tbl.CreatedAt)
}
orderApplied = true
}
if !orderApplied {
q = q.Order(tbl.CreatedAt.Desc())
}
filter.Pagination.Format()
total, err := q.Count()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
tenantMap, ownerMap, err := s.tenantMapsForTenantUsers(ctx, list)
if err != nil {
return nil, err
}
items := make([]super_dto.UserTenantItem, 0, len(list))
for _, tu := range list {
tenant := tenantMap[tu.TenantID]
owner := ownerMap[tu.TenantID]
item := super_dto.UserTenantItem{
TenantID: tu.TenantID,
Role: tu.Role,
MemberStatus: tu.Status,
MemberStatusDescription: tu.Status.Description(),
JoinedAt: s.formatTime(tu.CreatedAt),
}
if tenant != nil {
item.TenantStatus = tenant.Status
item.TenantStatusDescription = tenant.Status.Description()
item.Name = tenant.Name
item.Code = tenant.Code
item.ExpiredAt = s.formatTime(tenant.ExpiredAt)
}
if owner != nil {
item.Owner = &super_dto.TenantOwnerUserLite{
ID: owner.ID,
Username: owner.Username,
}
}
items = append(items, item)
}
return &requests.Pager{
Pagination: filter.Pagination,
Total: total,
Items: items,
}, nil
}
func (s *super) ListContents(ctx context.Context, filter *super_dto.SuperContentListFilter) (*requests.Pager, error) {
tbl, q := models.ContentQuery.QueryContext(ctx)
@@ -804,6 +1183,22 @@ func (s *super) toSuperUserDTO(u *models.User) *super_dto.User {
}
}
func (s *super) toSuperUserLite(u *models.User) *super_dto.SuperUserLite {
if u == nil {
return nil
}
return &super_dto.SuperUserLite{
ID: u.ID,
Username: u.Username,
Roles: u.Roles,
Status: u.Status,
StatusDescription: u.Status.Description(),
VerifiedAt: s.formatTime(u.VerifiedAt),
CreatedAt: s.formatTime(u.CreatedAt),
UpdatedAt: s.formatTime(u.UpdatedAt),
}
}
func hasRole(roles types.Array[consts.Role], role consts.Role) bool {
for _, r := range roles {
if r == role {
@@ -813,6 +1208,15 @@ func hasRole(roles types.Array[consts.Role], role consts.Role) bool {
return false
}
func hasTenantRole(roles types.Array[consts.TenantUserRole], role consts.TenantUserRole) bool {
for _, r := range roles {
if r == role {
return true
}
}
return false
}
func (s *super) buildSuperOrderItems(ctx context.Context, orders []*models.Order) ([]super_dto.SuperOrderItem, error) {
if len(orders) == 0 {
return []super_dto.SuperOrderItem{}, nil
@@ -1212,6 +1616,139 @@ func (s *super) toSuperDiscountValue(price *models.ContentPrice) float64 {
return float64(price.DiscountValue)
}
func (s *super) buildTenantItems(ctx context.Context, list []*models.Tenant) ([]super_dto.TenantItem, error) {
if len(list) == 0 {
return []super_dto.TenantItem{}, nil
}
tenantIDs := make([]int64, 0, len(list))
tenantOwnerIDs := make(map[int64]struct{}, len(list))
for _, t := range list {
tenantIDs = append(tenantIDs, t.ID)
tenantOwnerIDs[t.UserID] = struct{}{}
}
// 统计租户成员数与管理员列表(基于 tenant_users
userCountMap := make(map[int64]int64, len(list))
adminSet := make(map[int64]map[int64]struct{}, len(list))
tblTu, qTu := models.TenantUserQuery.QueryContext(ctx)
tenantUsers, err := qTu.Where(tblTu.TenantID.In(tenantIDs...)).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, tu := range tenantUsers {
userCountMap[tu.TenantID]++
if hasTenantRole(tu.Role, consts.TenantUserRoleTenantAdmin) {
if _, ok := adminSet[tu.TenantID]; !ok {
adminSet[tu.TenantID] = make(map[int64]struct{})
}
adminSet[tu.TenantID][tu.UserID] = struct{}{}
}
}
adminIDs := make(map[int64]struct{})
for _, ids := range adminSet {
for id := range ids {
adminIDs[id] = struct{}{}
}
}
userIDs := make([]int64, 0, len(adminIDs)+len(tenantOwnerIDs))
seen := make(map[int64]struct{})
for id := range adminIDs {
seen[id] = struct{}{}
userIDs = append(userIDs, id)
}
for id := range tenantOwnerIDs {
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
userIDs = append(userIDs, id)
}
userMap := make(map[int64]*models.User, len(userIDs))
if len(userIDs) > 0 {
tblUser, qUser := models.UserQuery.QueryContext(ctx)
users, err := qUser.Where(tblUser.ID.In(userIDs...)).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, u := range users {
userMap[u.ID] = u
}
}
// 汇总租户收入(按已支付/退款中/已退款订单统计实付金额)。
incomeMap := make(map[int64]int64, len(list))
if len(tenantIDs) > 0 {
var rows []struct {
TenantID int64 `gorm:"column:tenant_id"`
AmountPaidSum int64 `gorm:"column:amount_paid_sum"`
}
err := models.OrderQuery.WithContext(ctx).
UnderlyingDB().
Model(&models.Order{}).
Select("tenant_id, coalesce(sum(amount_paid), 0) as amount_paid_sum").
Where("tenant_id IN ?", tenantIDs).
Where("status IN ?", []consts.OrderStatus{
consts.OrderStatusPaid,
consts.OrderStatusRefunding,
consts.OrderStatusRefunded,
}).
Group("tenant_id").
Scan(&rows).Error
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, row := range rows {
incomeMap[row.TenantID] = row.AmountPaidSum
}
}
items := make([]super_dto.TenantItem, 0, len(list))
for _, t := range list {
item := super_dto.TenantItem{
ID: t.ID,
UUID: t.UUID.String(),
Name: t.Name,
Code: t.Code,
Status: t.Status,
StatusDescription: t.Status.Description(),
UserID: t.UserID,
UserCount: userCountMap[t.ID],
IncomeAmountPaidSum: incomeMap[t.ID],
ExpiredAt: s.formatTime(t.ExpiredAt),
CreatedAt: s.formatTime(t.CreatedAt),
UpdatedAt: s.formatTime(t.UpdatedAt),
}
if owner := userMap[t.UserID]; owner != nil {
item.Owner = &super_dto.TenantOwnerUserLite{
ID: owner.ID,
Username: owner.Username,
}
}
if adminSet[t.ID] != nil {
admins := make([]*super_dto.TenantAdminUserLite, 0, len(adminSet[t.ID]))
for adminID := range adminSet[t.ID] {
if u := userMap[adminID]; u != nil {
admins = append(admins, &super_dto.TenantAdminUserLite{
ID: u.ID,
Username: u.Username,
})
}
}
item.AdminUsers = admins
}
items = append(items, item)
}
return items, nil
}
func (s *super) ListWithdrawals(ctx context.Context, filter *super_dto.SuperOrderListFilter) (*requests.Pager, error) {
tbl, q := models.OrderQuery.QueryContext(ctx)
q = q.Where(tbl.Type.Eq(consts.OrderTypeWithdrawal))
@@ -1259,6 +1796,161 @@ func (s *super) ApproveWithdrawal(ctx context.Context, id int64) error {
return err
}
func (s *super) userOwnedTenantCount(ctx context.Context, userIDs []int64) (map[int64]int64, error) {
result := make(map[int64]int64, len(userIDs))
if len(userIDs) == 0 {
return result, nil
}
var rows []struct {
UserID int64 `gorm:"column:user_id"`
Count int64 `gorm:"column:count"`
}
err := models.TenantQuery.WithContext(ctx).
UnderlyingDB().
Model(&models.Tenant{}).
Select("user_id, count(*) as count").
Where("user_id IN ?", userIDs).
Group("user_id").
Scan(&rows).Error
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, row := range rows {
result[row.UserID] = row.Count
}
return result, nil
}
func (s *super) userJoinedTenantCount(ctx context.Context, userIDs []int64) (map[int64]int64, error) {
result := make(map[int64]int64, len(userIDs))
if len(userIDs) == 0 {
return result, nil
}
var rows []struct {
UserID int64 `gorm:"column:user_id"`
Count int64 `gorm:"column:count"`
}
err := models.TenantUserQuery.WithContext(ctx).
UnderlyingDB().
Model(&models.TenantUser{}).
Select("user_id, count(*) as count").
Where("user_id IN ?", userIDs).
Group("user_id").
Scan(&rows).Error
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, row := range rows {
result[row.UserID] = row.Count
}
return result, nil
}
func (s *super) userMapByTenantUsers(ctx context.Context, list []*models.TenantUser) (map[int64]*models.User, error) {
userIDs := make([]int64, 0, len(list))
seen := make(map[int64]struct{}, len(list))
for _, tu := range list {
if _, ok := seen[tu.UserID]; ok {
continue
}
seen[tu.UserID] = struct{}{}
userIDs = append(userIDs, tu.UserID)
}
userMap := make(map[int64]*models.User, len(userIDs))
if len(userIDs) == 0 {
return userMap, nil
}
tblUser, qUser := models.UserQuery.QueryContext(ctx)
users, err := qUser.Where(tblUser.ID.In(userIDs...)).Find()
if err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, u := range users {
userMap[u.ID] = u
}
return userMap, nil
}
func (s *super) toSuperTenantUserDTO(tu *models.TenantUser) *super_dto.TenantUser {
if tu == nil {
return nil
}
return &super_dto.TenantUser{
ID: tu.ID,
TenantID: tu.TenantID,
UserID: tu.UserID,
Role: tu.Role,
Status: tu.Status,
CreatedAt: s.formatTime(tu.CreatedAt),
UpdatedAt: s.formatTime(tu.UpdatedAt),
}
}
func (s *super) tenantMapsForTenantUsers(ctx context.Context, list []*models.TenantUser) (map[int64]*models.Tenant, map[int64]*models.User, error) {
tenantIDs := make([]int64, 0, len(list))
seen := make(map[int64]struct{}, len(list))
for _, tu := range list {
if _, ok := seen[tu.TenantID]; ok {
continue
}
seen[tu.TenantID] = struct{}{}
tenantIDs = append(tenantIDs, tu.TenantID)
}
tenantMap := make(map[int64]*models.Tenant, len(tenantIDs))
ownerMap := make(map[int64]*models.User, len(tenantIDs))
if len(tenantIDs) == 0 {
return tenantMap, ownerMap, nil
}
tblTenant, qTenant := models.TenantQuery.QueryContext(ctx)
tenants, err := qTenant.Where(tblTenant.ID.In(tenantIDs...)).Find()
if err != nil {
return nil, nil, errorx.ErrDatabaseError.WithCause(err)
}
ownerIDs := make([]int64, 0, len(tenants))
ownerSeen := make(map[int64]struct{}, len(tenants))
for _, t := range tenants {
tenantMap[t.ID] = t
if _, ok := ownerSeen[t.UserID]; ok {
continue
}
ownerSeen[t.UserID] = struct{}{}
ownerIDs = append(ownerIDs, t.UserID)
}
userMap := make(map[int64]*models.User, len(ownerIDs))
if len(ownerIDs) > 0 {
tblUser, qUser := models.UserQuery.QueryContext(ctx)
users, err := qUser.Where(tblUser.ID.In(ownerIDs...)).Find()
if err != nil {
return nil, nil, errorx.ErrDatabaseError.WithCause(err)
}
for _, u := range users {
userMap[u.ID] = u
}
}
for tenantID, tenant := range tenantMap {
if tenant == nil {
continue
}
if owner := userMap[tenant.UserID]; owner != nil {
ownerMap[tenantID] = owner
}
}
return tenantMap, ownerMap, nil
}
func (s *super) formatTime(t time.Time) string {
if t.IsZero() {
return ""
}
return t.Format(time.RFC3339)
}
func (s *super) RejectWithdrawal(ctx context.Context, id int64, reason string) error {
err := models.Q.Transaction(func(tx *models.Query) error {
o, err := tx.Order.WithContext(ctx).Where(tx.Order.ID.Eq(id)).First()