feat: add superadmin member review and coupon ops
This commit is contained in:
@@ -768,6 +768,273 @@ func (s *super) ListTenantUsers(ctx context.Context, tenantID int64, filter *sup
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) ListTenantJoinRequests(ctx context.Context, filter *super_dto.SuperTenantJoinRequestListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperTenantJoinRequestListFilter{}
|
||||
}
|
||||
|
||||
tbl, q := models.TenantJoinRequestQuery.QueryContext(ctx)
|
||||
if filter.TenantID != nil && *filter.TenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(*filter.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(string(*filter.Status)))
|
||||
}
|
||||
|
||||
tenantIDs, tenantFilter, err := s.lookupTenantIDs(ctx, filter.TenantCode, filter.TenantName)
|
||||
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...))
|
||||
}
|
||||
}
|
||||
|
||||
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...))
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
filter.Pagination.Format()
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
list, err := q.Order(tbl.CreatedAt.Desc()).
|
||||
Offset(int(filter.Pagination.Offset())).
|
||||
Limit(int(filter.Pagination.Limit)).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
// 补齐租户与用户信息,便于前端展示。
|
||||
tenantMap := make(map[int64]*models.Tenant)
|
||||
userMap := make(map[int64]*models.User)
|
||||
if len(list) > 0 {
|
||||
tenantIDSet := make(map[int64]struct{})
|
||||
userIDSet := make(map[int64]struct{})
|
||||
for _, req := range list {
|
||||
if req.TenantID > 0 {
|
||||
tenantIDSet[req.TenantID] = struct{}{}
|
||||
}
|
||||
if req.UserID > 0 {
|
||||
userIDSet[req.UserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
tenantIDs := make([]int64, 0, len(tenantIDSet))
|
||||
for id := range tenantIDSet {
|
||||
tenantIDs = append(tenantIDs, id)
|
||||
}
|
||||
if len(tenantIDs) > 0 {
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenants, err := tenantQuery.Where(tenantTbl.ID.In(tenantIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tenant := range tenants {
|
||||
tenantMap[tenant.ID] = tenant
|
||||
}
|
||||
}
|
||||
|
||||
userIDs := make([]int64, 0, len(userIDSet))
|
||||
for id := range userIDSet {
|
||||
userIDs = append(userIDs, id)
|
||||
}
|
||||
if len(userIDs) > 0 {
|
||||
userTbl, userQuery := models.UserQuery.QueryContext(ctx)
|
||||
users, err := userQuery.Where(userTbl.ID.In(userIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, user := range users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]super_dto.SuperTenantJoinRequestItem, 0, len(list))
|
||||
for _, req := range list {
|
||||
tenant := tenantMap[req.TenantID]
|
||||
user := userMap[req.UserID]
|
||||
status := consts.TenantJoinRequestStatus(req.Status)
|
||||
statusDescription := status.Description()
|
||||
if statusDescription == "" {
|
||||
statusDescription = req.Status
|
||||
}
|
||||
|
||||
tenantCode := ""
|
||||
tenantName := ""
|
||||
if tenant != nil {
|
||||
tenantCode = tenant.Code
|
||||
tenantName = tenant.Name
|
||||
}
|
||||
username := ""
|
||||
if user != nil {
|
||||
username = user.Username
|
||||
}
|
||||
if username == "" && req.UserID > 0 {
|
||||
username = "ID:" + strconv.FormatInt(req.UserID, 10)
|
||||
}
|
||||
|
||||
items = append(items, super_dto.SuperTenantJoinRequestItem{
|
||||
ID: req.ID,
|
||||
TenantID: req.TenantID,
|
||||
TenantCode: tenantCode,
|
||||
TenantName: tenantName,
|
||||
UserID: req.UserID,
|
||||
Username: username,
|
||||
Status: req.Status,
|
||||
StatusDescription: statusDescription,
|
||||
Reason: req.Reason,
|
||||
DecidedAt: s.formatTime(req.DecidedAt),
|
||||
DecidedOperatorUserID: req.DecidedOperatorUserID,
|
||||
DecidedReason: req.DecidedReason,
|
||||
CreatedAt: s.formatTime(req.CreatedAt),
|
||||
UpdatedAt: s.formatTime(req.UpdatedAt),
|
||||
})
|
||||
}
|
||||
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) ReviewTenantJoinRequest(ctx context.Context, operatorID, requestID int64, form *v1_dto.TenantJoinReviewForm) error {
|
||||
if operatorID == 0 {
|
||||
return errorx.ErrUnauthorized.WithMsg("缺少操作者信息")
|
||||
}
|
||||
if form == nil {
|
||||
return errorx.ErrBadRequest.WithMsg("审核参数不能为空")
|
||||
}
|
||||
action := strings.ToLower(strings.TrimSpace(form.Action))
|
||||
if action != "approve" && action != "reject" {
|
||||
return errorx.ErrBadRequest.WithMsg("审核动作无效")
|
||||
}
|
||||
|
||||
tblReq, qReq := models.TenantJoinRequestQuery.QueryContext(ctx)
|
||||
req, err := qReq.Where(tblReq.ID.Eq(requestID)).First()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errorx.ErrRecordNotFound.WithMsg("申请不存在")
|
||||
}
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if req.Status != string(consts.TenantJoinRequestStatusPending) {
|
||||
return errorx.ErrBadRequest.WithMsg("申请已处理")
|
||||
}
|
||||
|
||||
reason := strings.TrimSpace(form.Reason)
|
||||
now := time.Now()
|
||||
if action == "reject" {
|
||||
_, err = qReq.Where(
|
||||
tblReq.ID.Eq(req.ID),
|
||||
tblReq.Status.Eq(string(consts.TenantJoinRequestStatusPending)),
|
||||
).UpdateSimple(
|
||||
tblReq.Status.Value(string(consts.TenantJoinRequestStatusRejected)),
|
||||
tblReq.DecidedAt.Value(now),
|
||||
tblReq.DecidedOperatorUserID.Value(operatorID),
|
||||
tblReq.DecidedReason.Value(reason),
|
||||
)
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 审核通过需在事务内写入成员并更新申请状态。
|
||||
return models.Q.Transaction(func(tx *models.Query) error {
|
||||
tblMember, qMember := tx.TenantUser.QueryContext(ctx)
|
||||
exists, err := qMember.Where(
|
||||
tblMember.TenantID.Eq(req.TenantID),
|
||||
tblMember.UserID.Eq(req.UserID),
|
||||
).Exists()
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if exists {
|
||||
return errorx.ErrBadRequest.WithMsg("用户已是成员")
|
||||
}
|
||||
|
||||
member := &models.TenantUser{
|
||||
TenantID: req.TenantID,
|
||||
UserID: req.UserID,
|
||||
Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember},
|
||||
Status: consts.UserStatusVerified,
|
||||
}
|
||||
if err := qMember.Create(member); err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
tblReqTx, qReqTx := tx.TenantJoinRequest.QueryContext(ctx)
|
||||
_, err = qReqTx.Where(
|
||||
tblReqTx.ID.Eq(req.ID),
|
||||
tblReqTx.Status.Eq(string(consts.TenantJoinRequestStatusPending)),
|
||||
).UpdateSimple(
|
||||
tblReqTx.Status.Value(string(consts.TenantJoinRequestStatusApproved)),
|
||||
tblReqTx.DecidedAt.Value(now),
|
||||
tblReqTx.DecidedOperatorUserID.Value(operatorID),
|
||||
tblReqTx.DecidedReason.Value(reason),
|
||||
)
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *super) CreateTenantInvite(ctx context.Context, tenantID int64, form *v1_dto.TenantInviteCreateForm) (*v1_dto.TenantInviteItem, error) {
|
||||
if tenantID == 0 {
|
||||
return nil, errorx.ErrRecordNotFound.WithMsg("租户不存在")
|
||||
}
|
||||
|
||||
// 使用租户主账号执行创建邀请码逻辑,复用既有校验流程。
|
||||
tbl, q := models.TenantQuery.QueryContext(ctx)
|
||||
tenant, err := q.Where(tbl.ID.Eq(tenantID)).First()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errorx.ErrRecordNotFound.WithMsg("租户不存在")
|
||||
}
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
return Tenant.CreateInvite(ctx, tenantID, tenant.UserID, form)
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
Reference in New Issue
Block a user