Files
Wang Defa dbba1f4905
CI / test (push) Successful in 30s
Release / release (push) Successful in 49s
发布 0.1.0:通知渠道、告警规则、令牌版本与安全加固
2026-07-10 17:38:34 +08:00

202 lines
8.1 KiB
Go

package service
import (
"context"
"fmt"
"strings"
"oci-portal/internal/model"
"oci-portal/internal/oci"
)
// homeRegionOf 返回配置的 home region 名称;本地表查不到时退回默认区域。
// 用户管理等 IAM 写操作必须发往 home region。
func homeRegionOf(cfg *model.OciConfig) string {
if info, ok := oci.RegionByKey(cfg.HomeRegionKey); ok {
return info.Name
}
return cfg.Region
}
// credentialsAndHomeRegion 一次取回凭据与 home region。
func (s *OciConfigService) credentialsAndHomeRegion(ctx context.Context, id uint) (oci.Credentials, string, error) {
cfg, err := s.Get(ctx, id)
if err != nil {
return oci.Credentials{}, "", err
}
cred, err := s.credentialsOf(cfg)
if err != nil {
return oci.Credentials{}, "", err
}
return cred, homeRegionOf(cfg), nil
}
// IdentityDomains 列出租户全部 ACTIVE 身份域(域选择器数据源)。
func (s *OciConfigService) IdentityDomains(ctx context.Context, id uint) ([]oci.IdentityDomain, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return nil, err
}
return s.client.ListIdentityDomains(ctx, cred, homeRegion)
}
// TenantUsers 列出租户 IAM 用户;domainID 非空只列该身份域。
func (s *OciConfigService) TenantUsers(ctx context.Context, id uint, domainID string) ([]oci.TenantUser, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return nil, err
}
return s.client.ListTenantUsers(ctx, cred, homeRegion, domainID)
}
// TenantUserDetail 查用户的域档案与管理员状态(编辑表单预填充用)。
func (s *OciConfigService) TenantUserDetail(ctx context.Context, id uint, domainID, userID string) (oci.TenantUserDetail, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.TenantUserDetail{}, err
}
return s.client.GetTenantUserDetail(ctx, cred, homeRegion, domainID, userID)
}
// CreateTenantUser 新增用户;名字与姓氏必填(域用户档案要求),
// 描述缺省用「名 姓」。
func (s *OciConfigService) CreateTenantUser(ctx context.Context, id uint, domainID string, in oci.CreateTenantUserInput) (oci.TenantUser, error) {
if strings.TrimSpace(in.Name) == "" {
return oci.TenantUser{}, fmt.Errorf("create tenant user: name is required")
}
if strings.TrimSpace(in.GivenName) == "" || strings.TrimSpace(in.FamilyName) == "" {
return oci.TenantUser{}, fmt.Errorf("create tenant user: givenName and familyName are required")
}
if in.Description == "" {
in.Description = strings.TrimSpace(in.GivenName + " " + in.FamilyName)
}
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.TenantUser{}, err
}
return s.client.CreateTenantUser(ctx, cred, homeRegion, domainID, in)
}
// UpdateTenantUser 编辑用户资料;nil 字段不修改,全 nil 报错。
func (s *OciConfigService) UpdateTenantUser(ctx context.Context, id uint, domainID, userID string, in oci.UpdateTenantUserInput) (oci.TenantUser, error) {
hasField := in.Description != nil || in.Email != nil || in.GivenName != nil || in.FamilyName != nil
hasAdmin := in.GrantDomainAdmin != nil || in.AddToAdminGroup != nil
if !hasField && !hasAdmin {
return oci.TenantUser{}, fmt.Errorf("update tenant user: nothing to update")
}
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.TenantUser{}, err
}
return s.client.UpdateTenantUser(ctx, cred, homeRegion, domainID, userID, in)
}
// IdentitySetting 读取域身份设置(当前只透出主邮箱必填开关)。
func (s *OciConfigService) IdentitySetting(ctx context.Context, id uint, domainID string) (oci.IdentitySettingInfo, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.IdentitySettingInfo{}, err
}
return s.client.GetIdentitySetting(ctx, cred, homeRegion, domainID)
}
// UpdateIdentitySetting 修改「用户需要提供主电子邮件地址」开关。
func (s *OciConfigService) UpdateIdentitySetting(ctx context.Context, id uint, domainID string, primaryEmailRequired bool) (oci.IdentitySettingInfo, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.IdentitySettingInfo{}, err
}
return s.client.UpdateIdentitySetting(ctx, cred, homeRegion, domainID, primaryEmailRequired)
}
// DeleteTenantUser 删除 IAM 用户;拒绝删除当前配置正在使用的用户。
func (s *OciConfigService) DeleteTenantUser(ctx context.Context, id uint, domainID, userID string) error {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return err
}
if userID == cred.UserOCID {
return fmt.Errorf("delete tenant user: refusing to delete the user this config signs requests with")
}
return s.client.DeleteTenantUser(ctx, cred, homeRegion, domainID, userID)
}
// ResetTenantUserPassword 重置用户控制台密码,返回一次性新密码。
func (s *OciConfigService) ResetTenantUserPassword(ctx context.Context, id uint, domainID, userID string) (string, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return "", err
}
return s.client.ResetTenantUserPassword(ctx, cred, homeRegion, domainID, userID)
}
// DeleteTenantUserMfa 清除用户全部 MFA,返回删除的经典 TOTP 设备数。
func (s *OciConfigService) DeleteTenantUserMfa(ctx context.Context, id uint, domainID, userID string) (int, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return 0, err
}
return s.client.DeleteTenantUserMfaDevices(ctx, cred, homeRegion, domainID, userID)
}
// DeleteTenantUserApiKeys 删除用户的 API Key;默认保留当前配置使用的指纹。
func (s *OciConfigService) DeleteTenantUserApiKeys(ctx context.Context, id uint, userID string, includeCurrent bool) (int, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return 0, err
}
return s.client.DeleteTenantUserApiKeys(ctx, cred, homeRegion, userID, includeCurrent)
}
// NotificationRecipients 查询域通知收件人设置。
func (s *OciConfigService) NotificationRecipients(ctx context.Context, id uint, domainID string) (oci.NotificationRecipients, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.NotificationRecipients{}, err
}
return s.client.GetNotificationRecipients(ctx, cred, homeRegion, domainID)
}
// UpdateNotificationRecipients 把域通知改为只发给指定收件人;
// 收件人为空表示关闭 test mode 恢复默认发送。
func (s *OciConfigService) UpdateNotificationRecipients(ctx context.Context, id uint, domainID string, emails []string) (oci.NotificationRecipients, error) {
if err := validateEmails(emails); err != nil {
return oci.NotificationRecipients{}, err
}
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.NotificationRecipients{}, err
}
return s.client.UpdateNotificationRecipients(ctx, cred, homeRegion, domainID, emails)
}
func validateEmails(emails []string) error {
for _, email := range emails {
if !strings.Contains(email, "@") || strings.ContainsAny(email, " \t") {
return fmt.Errorf("update notification recipients: invalid email %q", email)
}
}
return nil
}
// PasswordPolicies 列出域密码策略。
func (s *OciConfigService) PasswordPolicies(ctx context.Context, id uint, domainID string) ([]oci.PasswordPolicyInfo, error) {
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return nil, err
}
return s.client.ListPasswordPolicies(ctx, cred, homeRegion, domainID)
}
// UpdatePasswordPolicy 修改域密码策略的过期天数或最小长度。
func (s *OciConfigService) UpdatePasswordPolicy(ctx context.Context, id uint, domainID, policyID string, in oci.UpdatePasswordPolicyInput) (oci.PasswordPolicyInfo, error) {
if in.PasswordExpiresAfter == nil && in.MinLength == nil {
return oci.PasswordPolicyInfo{}, fmt.Errorf("update password policy: nothing to update")
}
cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
if err != nil {
return oci.PasswordPolicyInfo{}, err
}
return s.client.UpdatePasswordPolicy(ctx, cred, homeRegion, domainID, policyID, in)
}