Files
MAcode/tcs-iptv/internal/service/admin.go
T

266 lines
6.8 KiB
Go

package service
import (
"crypto/rand"
"encoding/hex"
"fmt"
"sync"
"time"
"github.com/tcs-iptv/tcs/internal/model"
)
// AdminService 用户管理/组织管理服务(系统管理模块补足)。
// MVP 使用内存存储,生产环境可替换为 PostgreSQL 实现。
type AdminService struct {
mu sync.RWMutex
users map[string]*model.User // userID -> User
orgs map[string]*model.Organization // orgID -> Organization
keys map[string]*model.User // apiKey -> User(快速鉴权查找)
names map[string]bool // username 唯一性校验
}
// NewAdminService 创建用户/组织管理服务。
func NewAdminService() *AdminService {
return &AdminService{
users: make(map[string]*model.User),
orgs: make(map[string]*model.Organization),
keys: make(map[string]*model.User),
names: make(map[string]bool),
}
}
// ---- 组织管理 ----
// CreateOrg 创建组织。
func (a *AdminService) CreateOrg(org model.Organization) (model.Organization, error) {
if org.Name == "" {
return model.Organization{}, fmt.Errorf("admin: 组织名称不能为空")
}
a.mu.Lock()
defer a.mu.Unlock()
org.ID = a.nextID("org")
org.Status = model.OrgStatusActive
if org.CreatedAt.IsZero() {
org.CreatedAt = time.Now()
}
org.UpdatedAt = time.Now()
a.orgs[org.ID] = &org
return org, nil
}
// UpdateOrg 更新组织信息。
func (a *AdminService) UpdateOrg(orgID string, updates model.Organization) (model.Organization, error) {
a.mu.Lock()
defer a.mu.Unlock()
org, ok := a.orgs[orgID]
if !ok {
return model.Organization{}, fmt.Errorf("admin: 组织 %s 不存在", orgID)
}
if updates.Name != "" {
org.Name = updates.Name
}
if updates.OrgNode != "" {
org.OrgNode = updates.OrgNode
}
if updates.Province != "" {
org.Province = updates.Province
}
if updates.Type != "" {
org.Type = updates.Type
}
if updates.Status != "" {
org.Status = updates.Status
}
org.UpdatedAt = time.Now()
return *org, nil
}
// GetOrg 查询组织详情。
func (a *AdminService) GetOrg(orgID string) (model.Organization, error) {
a.mu.RLock()
defer a.mu.RUnlock()
org, ok := a.orgs[orgID]
if !ok {
return model.Organization{}, fmt.Errorf("admin: 组织 %s 不存在", orgID)
}
return *org, nil
}
// ListOrgs 列出全部组织(可按类型过滤)。
func (a *AdminService) ListOrgs(orgType string) []model.Organization {
a.mu.RLock()
defer a.mu.RUnlock()
var out []model.Organization
for _, org := range a.orgs {
if orgType == "" || org.Type == orgType {
out = append(out, *org)
}
}
return out
}
// DisableOrg 禁用组织。
func (a *AdminService) DisableOrg(orgID string) error {
a.mu.Lock()
defer a.mu.Unlock()
org, ok := a.orgs[orgID]
if !ok {
return fmt.Errorf("admin: 组织 %s 不存在", orgID)
}
org.Status = model.OrgStatusDisabled
org.UpdatedAt = time.Now()
return nil
}
// ---- 用户管理 ----
// CreateUser 创建用户并自动生成 API Key/Secret。
func (a *AdminService) CreateUser(user model.User) (model.User, error) {
if user.Username == "" {
return model.User{}, fmt.Errorf("admin: 用户名不能为空")
}
if user.OrgID == "" {
return model.User{}, fmt.Errorf("admin: 所属组织不能为空")
}
a.mu.Lock()
defer a.mu.Unlock()
if a.names[user.Username] {
return model.User{}, fmt.Errorf("admin: 用户名 %s 已存在", user.Username)
}
if _, ok := a.orgs[user.OrgID]; !ok {
return model.User{}, fmt.Errorf("admin: 组织 %s 不存在", user.OrgID)
}
user.ID = a.nextID("user")
user.APIKey = a.generateAPIKey()
user.APISecret = a.generateAPISecret()
user.Status = model.UserStatusActive
if user.CreatedAt.IsZero() {
user.CreatedAt = time.Now()
}
user.UpdatedAt = time.Now()
a.users[user.ID] = &user
a.keys[user.APIKey] = &user
a.names[user.Username] = true
return user, nil
}
// UpdateUser 更新用户信息(不支持修改用户名和 API Key)。
func (a *AdminService) UpdateUser(userID string, updates model.User) (model.User, error) {
a.mu.Lock()
defer a.mu.Unlock()
user, ok := a.users[userID]
if !ok {
return model.User{}, fmt.Errorf("admin: 用户 %s 不存在", userID)
}
if updates.FullName != "" {
user.FullName = updates.FullName
}
if updates.OrgID != "" {
if _, ok := a.orgs[updates.OrgID]; !ok {
return model.User{}, fmt.Errorf("admin: 组织 %s 不存在", updates.OrgID)
}
user.OrgID = updates.OrgID
}
if updates.Role != "" {
user.Role = updates.Role
}
if updates.Status != "" {
user.Status = updates.Status
}
user.UpdatedAt = time.Now()
return *user, nil
}
// GetUser 查询用户详情。
func (a *AdminService) GetUser(userID string) (model.User, error) {
a.mu.RLock()
defer a.mu.RUnlock()
user, ok := a.users[userID]
if !ok {
return model.User{}, fmt.Errorf("admin: 用户 %s 不存在", userID)
}
return *user, nil
}
// ListUsers 列出全部用户(可按组织或角色过滤)。
func (a *AdminService) ListUsers(orgID, role string) []model.User {
a.mu.RLock()
defer a.mu.RUnlock()
var out []model.User
for _, user := range a.users {
if orgID != "" && user.OrgID != orgID {
continue
}
if role != "" && user.Role != role {
continue
}
out = append(out, *user)
}
return out
}
// DisableUser 禁用用户。
func (a *AdminService) DisableUser(userID string) error {
a.mu.Lock()
defer a.mu.Unlock()
user, ok := a.users[userID]
if !ok {
return fmt.Errorf("admin: 用户 %s 不存在", userID)
}
user.Status = model.UserStatusDisabled
user.UpdatedAt = time.Now()
return nil
}
// ResetAPIKey 重置用户的 API Key 和 Secret。
func (a *AdminService) ResetAPIKey(userID string) (model.User, error) {
a.mu.Lock()
defer a.mu.Unlock()
user, ok := a.users[userID]
if !ok {
return model.User{}, fmt.Errorf("admin: 用户 %s 不存在", userID)
}
// 移除旧 key
delete(a.keys, user.APIKey)
// 生成新 key
user.APIKey = a.generateAPIKey()
user.APISecret = a.generateAPISecret()
user.UpdatedAt = time.Now()
a.keys[user.APIKey] = user
return *user, nil
}
// LookupByAPIKey 根据 API Key 查询用户(供 httpx.KeyStore 使用)。
func (a *AdminService) LookupByAPIKey(apiKey string) (secret string, role string, ok bool) {
a.mu.RLock()
defer a.mu.RUnlock()
user, exists := a.keys[apiKey]
if !exists || user.Status != model.UserStatusActive {
return "", "", false
}
return user.APISecret, user.Role, true
}
// ---- 辅助方法 ----
func (a *AdminService) nextID(prefix string) string {
// 使用时间戳+随机数生成唯一 ID
ts := time.Now().Format("20060102")
b := make([]byte, 4)
rand.Read(b)
return fmt.Sprintf("%s-%s-%s", prefix, ts, hex.EncodeToString(b))
}
func (a *AdminService) generateAPIKey() string {
b := make([]byte, 16)
rand.Read(b)
return "tcs-" + hex.EncodeToString(b)
}
func (a *AdminService) generateAPISecret() string {
b := make([]byte, 32)
rand.Read(b)
return hex.EncodeToString(b)
}