org 模块: - tenants 表 (UUID PK, name, slug, status, settings) - 完整 CRUD API: /api/v1/org/tenants - 多租户隔离 audit 模块: - audit_logs 表 (actor, action, resource, IP, 时间) - 查询 API: /api/v1/audit/logs (支持分页+筛选) - 按 tenant_id/user_id/action/resource 过滤
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
package application
|
|
|
|
import (
|
|
"context"
|
|
|
|
"mengstack/internal/kernel/errors"
|
|
"mengstack/internal/modules/org/domain"
|
|
)
|
|
|
|
type Service struct {
|
|
repo domain.TenantRepository
|
|
}
|
|
|
|
func NewService(repo domain.TenantRepository) *Service {
|
|
return &Service{repo: repo}
|
|
}
|
|
|
|
func (s *Service) CreateTenant(ctx context.Context, req domain.CreateTenantRequest) (domain.TenantDTO, error) {
|
|
if _, err := s.repo.FindBySlug(ctx, req.Slug); err == nil {
|
|
return domain.TenantDTO{}, errors.ErrConflict
|
|
}
|
|
|
|
tenant := &domain.Tenant{
|
|
Name: req.Name,
|
|
Slug: req.Slug,
|
|
}
|
|
|
|
if err := s.repo.Create(ctx, tenant); err != nil {
|
|
return domain.TenantDTO{}, errors.Wrap(err, "CREATE_TENANT_FAILED", "failed to create tenant", 500)
|
|
}
|
|
|
|
return domain.ToTenantDTO(tenant), nil
|
|
}
|
|
|
|
func (s *Service) ListTenants(ctx context.Context) ([]domain.TenantDTO, error) {
|
|
tenants, err := s.repo.FindAll(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "QUERY_TENANTS_FAILED", "failed to query tenants", 500)
|
|
}
|
|
|
|
dtos := make([]domain.TenantDTO, len(tenants))
|
|
for i, t := range tenants {
|
|
dtos[i] = domain.ToTenantDTO(&t)
|
|
}
|
|
return dtos, nil
|
|
}
|
|
|
|
func (s *Service) GetTenant(ctx context.Context, id string) (domain.TenantDTO, error) {
|
|
tenant, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return domain.TenantDTO{}, errors.ErrNotFound
|
|
}
|
|
|
|
return domain.ToTenantDTO(tenant), nil
|
|
}
|
|
|
|
func (s *Service) UpdateTenant(ctx context.Context, id string, req domain.UpdateTenantRequest) (domain.TenantDTO, error) {
|
|
tenant, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return domain.TenantDTO{}, errors.ErrNotFound
|
|
}
|
|
|
|
if req.Name != "" {
|
|
tenant.Name = req.Name
|
|
}
|
|
if req.Slug != "" {
|
|
if existing, err := s.repo.FindBySlug(ctx, req.Slug); err == nil && existing.ID != id {
|
|
return domain.TenantDTO{}, errors.ErrConflict
|
|
}
|
|
tenant.Slug = req.Slug
|
|
}
|
|
if req.Status != nil {
|
|
tenant.Status = *req.Status
|
|
}
|
|
|
|
if err := s.repo.Update(ctx, tenant); err != nil {
|
|
return domain.TenantDTO{}, errors.Wrap(err, "UPDATE_TENANT_FAILED", "failed to update tenant", 500)
|
|
}
|
|
|
|
return domain.ToTenantDTO(tenant), nil
|
|
}
|
|
|
|
func (s *Service) DeleteTenant(ctx context.Context, id string) error {
|
|
if _, err := s.repo.FindByID(ctx, id); err != nil {
|
|
return errors.ErrNotFound
|
|
}
|
|
|
|
if err := s.repo.Delete(ctx, id); err != nil {
|
|
return errors.Wrap(err, "DELETE_TENANT_FAILED", "failed to delete tenant", 500)
|
|
}
|
|
|
|
return nil
|
|
}
|