package tenant import ( "strings" "quyun/v2/app/errorx" "quyun/v2/app/http/tenant/dto" "quyun/v2/app/requests" "quyun/v2/app/services" "quyun/v2/database/models" "quyun/v2/pkg/consts" "github.com/gofiber/fiber/v3" log "github.com/sirupsen/logrus" "go.ipao.vip/gen" ) // tenantUserAdmin provides tenant-admin member management endpoints. // // @provider type tenantUserAdmin struct{} // adminJoinUser // // @Summary 添加租户成员(租户管理) // @Tags Tenant // @Accept json // @Produce json // @Param tenantCode path string true "Tenant Code" // @Param userID path int64 true "UserID" // @Success 200 {object} dto.AdminTenantUserJoinResponse // // @Router /t/:tenantCode/v1/admin/users/:userID/join [post] // @Bind tenant local key(tenant) // @Bind tenantUser local key(tenant_user) // @Bind userID path func (*tenantUserAdmin) adminJoinUser( ctx fiber.Ctx, tenant *models.Tenant, tenantUser *models.TenantUser, userID int64, ) (*dto.AdminTenantUserJoinResponse, error) { if err := requireTenantAdmin(tenantUser); err != nil { return nil, err } if userID <= 0 { return nil, errorx.ErrInvalidParameter.WithMsg("user_id must be > 0") } log.WithFields(log.Fields{ "tenant_id": tenant.ID, "operator_user_id": tenantUser.UserID, "target_user_id": userID, "operator_is_admin": true, }).Info("tenant.admin.users.join") // 关键逻辑:以 TenantUser 为准创建成员关系;服务层保证幂等(已存在则不重复创建)。 if err := services.Tenant.AddUser(ctx.Context(), tenant.ID, userID); err != nil { return nil, err } m, err := services.Tenant.FindTenantUser(ctx.Context(), tenant.ID, userID) if err != nil { return nil, err } return &dto.AdminTenantUserJoinResponse{TenantUser: m}, nil } // adminSetUserRole // // @Summary 设置成员角色(租户管理) // @Tags Tenant // @Accept json // @Produce json // @Param tenantCode path string true "Tenant Code" // @Param userID path int64 true "UserID" // @Param form body dto.AdminTenantUserRoleUpdateForm true "Form" // @Success 200 {object} dto.AdminTenantUserJoinResponse // // @Router /t/:tenantCode/v1/admin/users/:userID/role [patch] // @Bind tenant local key(tenant) // @Bind tenantUser local key(tenant_user) // @Bind userID path // @Bind form body func (*tenantUserAdmin) adminSetUserRole( ctx fiber.Ctx, tenant *models.Tenant, tenantUser *models.TenantUser, userID int64, form *dto.AdminTenantUserRoleUpdateForm, ) (*dto.AdminTenantUserJoinResponse, error) { if err := requireTenantAdmin(tenantUser); err != nil { return nil, err } if userID <= 0 || form == nil { return nil, errorx.ErrInvalidParameter } roleStr := strings.TrimSpace(form.Role) if roleStr == "" { return nil, errorx.ErrInvalidParameter.WithMsg("role is required") } var role consts.TenantUserRole switch roleStr { case string(consts.TenantUserRoleMember): role = consts.TenantUserRoleMember case string(consts.TenantUserRoleTenantAdmin): role = consts.TenantUserRoleTenantAdmin default: return nil, errorx.ErrInvalidParameter.WithMsg("invalid role") } log.WithFields(log.Fields{ "tenant_id": tenant.ID, "operator_user_id": tenantUser.UserID, "target_user_id": userID, "role": role, }).Info("tenant.admin.users.set_role") if err := services.Tenant.SetUserRole(ctx.Context(), tenant.ID, userID, role); err != nil { return nil, err } m, err := services.Tenant.FindTenantUser(ctx.Context(), tenant.ID, userID) if err != nil { return nil, err } return &dto.AdminTenantUserJoinResponse{TenantUser: m}, nil } // adminTenantUsers // // @Summary 成员列表(租户管理) // @Tags Tenant // @Accept json // @Produce json // @Param tenantCode path string true "Tenant Code" // @Param filter query dto.AdminTenantUserListFilter true "Filter" // @Success 200 {object} requests.Pager{items=models.TenantUser} // // @Router /t/:tenantCode/v1/admin/users [get] // @Bind tenant local key(tenant) // @Bind tenantUser local key(tenant_user) // @Bind filter query func (*tenantUserAdmin) adminTenantUsers( ctx fiber.Ctx, tenant *models.Tenant, tenantUser *models.TenantUser, filter *dto.AdminTenantUserListFilter, ) (*requests.Pager, error) { if err := requireTenantAdmin(tenantUser); err != nil { return nil, err } if filter == nil { filter = &dto.AdminTenantUserListFilter{} } log.WithFields(log.Fields{ "tenant_id": tenant.ID, "user_id": tenantUser.UserID, "query_uid": filter.UserID, }).Info("tenant.admin.users.list") filter.Pagination.Format() tbl, query := models.TenantUserQuery.QueryContext(ctx.Context()) conds := []gen.Condition{tbl.TenantID.Eq(tenant.ID)} if filter.UserID != nil && *filter.UserID > 0 { conds = append(conds, tbl.UserID.Eq(*filter.UserID)) } items, total, err := query.Where(conds...).Order(tbl.ID.Desc()).FindByPage(int(filter.Offset()), int(filter.Limit)) if err != nil { return nil, err } return &requests.Pager{ Pagination: filter.Pagination, Total: total, Items: items, }, nil }