Files
ai_site/platform/internal/logic/applogic/tenant_invite.go
whm cb56e6847e feat: add Z12/Z13 bind APIs, stock import, and sync docs
Enable auto default sync channels on agent activate, bind-code/phone confirm flows, publish ALTER, and align admin/yuheng docs with the production bind path.
2026-08-05 11:47:20 +08:00

156 lines
4.3 KiB
Go

package applogic
import (
"context"
"fmt"
"strings"
"time"
"aijianzhan/platform/internal/authx"
"aijianzhan/platform/internal/invitestore"
"aijianzhan/platform/internal/svc"
"aijianzhan/platform/internal/types"
"aijianzhan/platform/internal/userstore"
)
func (l *AuthLogic) issueUser(u *userstore.User) (*types.TokenResp, error) {
resp, err := l.issue(u.TenantID, u.UserID, u.Role, u.Username, u.DisplayName, u.OrgUnitID)
if err != nil {
return nil, err
}
resp.Phone = u.Phone
resp.UsernameLoginDisabled = u.UsernameLoginDisabled
resp.Status = u.Status
if resp.Status == "" {
if u.HasTenant() || u.IsPlatformAdmin() {
resp.Status = userstore.StatusActive
} else {
resp.Status = userstore.StatusPending
}
}
fillUserSyncOnToken(l.svcCtx, resp, u)
if u.IsPlatformAdmin() {
resp.Message = "平台超级管理员工作台:管理全部公司;打开某公司可查看其内部功能"
return resp, nil
}
if !u.HasTenant() {
resp.Message = "账号待加入租户:请使用邀请码加入公司,或创建自己的公司"
}
return resp, nil
}
func (l *AuthLogic) AcceptInvite(req *types.InviteAcceptReq) (*types.TokenResp, error) {
if l.svcCtx.Users == nil || l.svcCtx.Invites == nil {
return nil, fmt.Errorf("invite store unavailable")
}
code := strings.TrimSpace(req.Code)
if code == "" {
return nil, fmt.Errorf("invite code required")
}
userID := authx.UserID(l.ctx)
cur, err := l.svcCtx.Users.GetByID(l.ctx, userID)
if err != nil {
return nil, err
}
if cur.HasTenant() {
return nil, fmt.Errorf("already joined a tenant")
}
inv, err := l.svcCtx.Invites.GetByCode(l.ctx, code)
if err != nil {
return nil, fmt.Errorf("invalid invite code")
}
if err := invitestore.ValidateUsable(inv); err != nil {
return nil, err
}
if inv.OrgUnitID > 0 && l.svcCtx.OrgUnits != nil {
if _, err := l.svcCtx.OrgUnits.Get(l.ctx, inv.TenantID, inv.OrgUnitID); err != nil {
return nil, fmt.Errorf("invite org unit invalid")
}
}
if err := l.svcCtx.Invites.Consume(l.ctx, inv.InviteID); err != nil {
return nil, err
}
u, err := l.svcCtx.Users.JoinTenant(l.ctx, userID, inv.TenantID, inv.Role, inv.OrgUnitID)
if err != nil {
return nil, err
}
if l.svcCtx.Roles != nil {
_ = l.svcCtx.Roles.EnsureDefaults(l.ctx, u.TenantID)
}
resp, err := l.issueUser(u)
if err != nil {
return nil, err
}
resp.Message = "已加入租户"
return resp, nil
}
func (l *AuthLogic) CreateTenant(req *types.TenantCreateReq) (*types.TokenResp, error) {
if l.svcCtx.Users == nil {
return nil, fmt.Errorf("user store unavailable")
}
userID := authx.UserID(l.ctx)
u, err := l.svcCtx.Users.CreateTenantAsOwner(l.ctx, userID, req.Name)
if err != nil {
return nil, err
}
if l.svcCtx.Roles != nil {
_ = l.svcCtx.Roles.EnsureDefaults(l.ctx, u.TenantID)
}
if l.svcCtx.TenantPerm != nil {
_ = l.svcCtx.TenantPerm.EnsureDefault(l.ctx, u.TenantID)
}
resp, err := l.issueUser(u)
if err != nil {
return nil, err
}
resp.Message = "已创建公司并成为管理员"
return resp, nil
}
type InviteAdminLogic struct {
AuthLogic
}
func NewInviteAdminLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InviteAdminLogic {
return &InviteAdminLogic{AuthLogic: AuthLogic{ctx: ctx, svcCtx: svcCtx}}
}
func (l *InviteAdminLogic) List() ([]invitestore.Invite, error) {
if l.svcCtx.Invites == nil {
return nil, fmt.Errorf("invite store unavailable")
}
return l.svcCtx.Invites.List(l.ctx, authx.TenantID(l.ctx))
}
func (l *InviteAdminLogic) Create(req *types.InviteCreateReq) (*invitestore.Invite, error) {
if l.svcCtx.Invites == nil {
return nil, fmt.Errorf("invite store unavailable")
}
tid := authx.TenantID(l.ctx)
if req.OrgUnitID > 0 {
if l.svcCtx.OrgUnits == nil {
return nil, fmt.Errorf("org unit store unavailable")
}
if _, err := l.svcCtx.OrgUnits.Get(l.ctx, tid, req.OrgUnitID); err != nil {
return nil, fmt.Errorf("invalid org_unit_id")
}
}
in := invitestore.CreateInput{
Role: req.Role,
OrgUnitID: req.OrgUnitID,
MaxUses: req.MaxUses,
}
if req.ExpiresInHours > 0 {
in.ExpiresIn = time.Duration(req.ExpiresInHours) * time.Hour
}
return l.svcCtx.Invites.Create(l.ctx, tid, authx.UserID(l.ctx), in)
}
func (l *InviteAdminLogic) Revoke(inviteID int64) error {
if l.svcCtx.Invites == nil {
return fmt.Errorf("invite store unavailable")
}
return l.svcCtx.Invites.Revoke(l.ctx, authx.TenantID(l.ctx), inviteID)
}