|
|
|
@@ -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()
|
|
|
|
|