feat: 初始化 ChatGPT Team 管理后端项目

- 添加用户认证模块 (JWT + 密码管理)
- 添加 ChatGPT 账户管理功能
- 添加卡密管理功能 (创建、批量生成、查询)
- 添加邀请功能
- 配置数据库迁移和路由系统
This commit is contained in:
sar
2026-01-13 14:42:56 +08:00
commit 42c423bd32
29 changed files with 2969 additions and 0 deletions

View File

@@ -0,0 +1,207 @@
package repository
import (
"database/sql"
"time"
"gpt-manager-go/internal/models"
)
// ChatGPTAccountRepository ChatGPT 账号仓储
type ChatGPTAccountRepository struct {
db *sql.DB
}
// NewChatGPTAccountRepository 创建仓储
func NewChatGPTAccountRepository(db *sql.DB) *ChatGPTAccountRepository {
return &ChatGPTAccountRepository{db: db}
}
// Create 创建账号
func (r *ChatGPTAccountRepository) Create(account *models.ChatGPTAccount) error {
return r.db.QueryRow(`
INSERT INTO chatgpt_accounts (name, auth_token, team_account_id, seats_in_use, seats_entitled,
active_start, active_until, is_active, consecutive_failures, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id
`,
account.Name,
account.AuthToken,
account.TeamAccountID,
account.SeatsInUse,
account.SeatsEntitled,
account.ActiveStart,
account.ActiveUntil,
account.IsActive,
account.ConsecutiveFailures,
time.Now(),
).Scan(&account.ID)
}
// Update 更新账号
func (r *ChatGPTAccountRepository) Update(account *models.ChatGPTAccount) error {
_, err := r.db.Exec(`
UPDATE chatgpt_accounts SET
name = $1, auth_token = $2, seats_in_use = $3, seats_entitled = $4,
active_start = $5, active_until = $6, is_active = $7,
consecutive_failures = $8, last_check = $9, updated_at = $10
WHERE id = $11
`,
account.Name,
account.AuthToken,
account.SeatsInUse,
account.SeatsEntitled,
account.ActiveStart,
account.ActiveUntil,
account.IsActive,
account.ConsecutiveFailures,
account.LastCheck,
time.Now(),
account.ID,
)
return err
}
// FindByID 根据 ID 查找
func (r *ChatGPTAccountRepository) FindByID(id int) (*models.ChatGPTAccount, error) {
account := &models.ChatGPTAccount{}
err := r.db.QueryRow(`
SELECT id, name, auth_token, team_account_id, seats_in_use, seats_entitled,
active_start, active_until, is_active, consecutive_failures,
last_check, last_used, created_at, updated_at
FROM chatgpt_accounts WHERE id = $1
`, id).Scan(
&account.ID, &account.Name, &account.AuthToken, &account.TeamAccountID,
&account.SeatsInUse, &account.SeatsEntitled, &account.ActiveStart, &account.ActiveUntil,
&account.IsActive, &account.ConsecutiveFailures, &account.LastCheck,
&account.LastUsed, &account.CreatedAt, &account.UpdatedAt,
)
if err == sql.ErrNoRows {
return nil, nil
}
return account, err
}
// FindByTeamAccountID 根据 Team Account ID 查找
func (r *ChatGPTAccountRepository) FindByTeamAccountID(teamAccountID string) (*models.ChatGPTAccount, error) {
account := &models.ChatGPTAccount{}
err := r.db.QueryRow(`
SELECT id, name, auth_token, team_account_id, seats_in_use, seats_entitled,
active_start, active_until, is_active, consecutive_failures,
last_check, last_used, created_at, updated_at
FROM chatgpt_accounts WHERE team_account_id = $1
`, teamAccountID).Scan(
&account.ID, &account.Name, &account.AuthToken, &account.TeamAccountID,
&account.SeatsInUse, &account.SeatsEntitled, &account.ActiveStart, &account.ActiveUntil,
&account.IsActive, &account.ConsecutiveFailures, &account.LastCheck,
&account.LastUsed, &account.CreatedAt, &account.UpdatedAt,
)
if err == sql.ErrNoRows {
return nil, nil
}
return account, err
}
// FindAll 获取所有账号
func (r *ChatGPTAccountRepository) FindAll() ([]*models.ChatGPTAccount, error) {
rows, err := r.db.Query(`
SELECT id, name, auth_token, team_account_id, seats_in_use, seats_entitled,
active_start, active_until, is_active, consecutive_failures,
last_check, last_used, created_at, updated_at
FROM chatgpt_accounts ORDER BY created_at DESC
`)
if err != nil {
return nil, err
}
defer rows.Close()
var accounts []*models.ChatGPTAccount
for rows.Next() {
account := &models.ChatGPTAccount{}
if err := rows.Scan(
&account.ID, &account.Name, &account.AuthToken, &account.TeamAccountID,
&account.SeatsInUse, &account.SeatsEntitled, &account.ActiveStart, &account.ActiveUntil,
&account.IsActive, &account.ConsecutiveFailures, &account.LastCheck,
&account.LastUsed, &account.CreatedAt, &account.UpdatedAt,
); err != nil {
return nil, err
}
accounts = append(accounts, account)
}
return accounts, nil
}
// FindActive 获取所有激活的账号
func (r *ChatGPTAccountRepository) FindActive() ([]*models.ChatGPTAccount, error) {
rows, err := r.db.Query(`
SELECT id, name, auth_token, team_account_id, seats_in_use, seats_entitled,
active_start, active_until, is_active, consecutive_failures,
last_check, last_used, created_at, updated_at
FROM chatgpt_accounts WHERE is_active = true ORDER BY created_at DESC
`)
if err != nil {
return nil, err
}
defer rows.Close()
var accounts []*models.ChatGPTAccount
for rows.Next() {
account := &models.ChatGPTAccount{}
if err := rows.Scan(
&account.ID, &account.Name, &account.AuthToken, &account.TeamAccountID,
&account.SeatsInUse, &account.SeatsEntitled, &account.ActiveStart, &account.ActiveUntil,
&account.IsActive, &account.ConsecutiveFailures, &account.LastCheck,
&account.LastUsed, &account.CreatedAt, &account.UpdatedAt,
); err != nil {
return nil, err
}
accounts = append(accounts, account)
}
return accounts, nil
}
// Delete 删除账号
func (r *ChatGPTAccountRepository) Delete(id int) error {
_, err := r.db.Exec(`DELETE FROM chatgpt_accounts WHERE id = $1`, id)
return err
}
// FindActiveWithAvailableSeats 查找激活且有可用席位的账号
func (r *ChatGPTAccountRepository) FindActiveWithAvailableSeats() ([]*models.ChatGPTAccount, error) {
rows, err := r.db.Query(`
SELECT id, name, auth_token, team_account_id, seats_in_use, seats_entitled,
active_start, active_until, is_active, consecutive_failures,
last_check, last_used, created_at, updated_at
FROM chatgpt_accounts
WHERE is_active = true AND seats_entitled > seats_in_use
ORDER BY (seats_entitled - seats_in_use) DESC, last_used ASC NULLS FIRST
`)
if err != nil {
return nil, err
}
defer rows.Close()
var accounts []*models.ChatGPTAccount
for rows.Next() {
account := &models.ChatGPTAccount{}
if err := rows.Scan(
&account.ID, &account.Name, &account.AuthToken, &account.TeamAccountID,
&account.SeatsInUse, &account.SeatsEntitled, &account.ActiveStart, &account.ActiveUntil,
&account.IsActive, &account.ConsecutiveFailures, &account.LastCheck,
&account.LastUsed, &account.CreatedAt, &account.UpdatedAt,
); err != nil {
return nil, err
}
accounts = append(accounts, account)
}
return accounts, nil
}
// UpdateLastUsed 更新账号最后使用时间和席位
func (r *ChatGPTAccountRepository) UpdateLastUsed(id int) error {
_, err := r.db.Exec(`
UPDATE chatgpt_accounts SET last_used = $1, seats_in_use = seats_in_use + 1, updated_at = $1
WHERE id = $2
`, time.Now(), id)
return err
}