feat: implement ChatGPT owner demotion service with a FastAPI backend and a basic frontend, alongside updated project metadata.

This commit is contained in:
2026-02-05 07:18:22 +08:00
parent 8895d508c0
commit ad1270b88d
4 changed files with 402 additions and 8 deletions

View File

@@ -147,6 +147,20 @@ func (d *DB) createTables() error {
);
CREATE INDEX IF NOT EXISTS idx_codex_auth_proxies_enabled ON codex_auth_proxies(is_enabled);
-- 日志持久化表
CREATE TABLE IF NOT EXISTS app_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME NOT NULL,
level TEXT NOT NULL,
message TEXT NOT NULL,
email TEXT,
module TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_app_logs_timestamp ON app_logs(timestamp);
CREATE INDEX IF NOT EXISTS idx_app_logs_module ON app_logs(module);
CREATE INDEX IF NOT EXISTS idx_app_logs_level ON app_logs(level);
`)
return err
}
@@ -1008,6 +1022,186 @@ func (d *DB) GetCodexProxyStats() map[string]int {
return stats
}
// ========================
// 日志持久化相关方法
// ========================
// LogEntry 日志条目
type LogEntry struct {
ID int64 `json:"id"`
Timestamp time.Time `json:"timestamp"`
Level string `json:"level"`
Message string `json:"message"`
Email string `json:"email,omitempty"`
Module string `json:"module,omitempty"`
}
// InsertLog 插入日志
func (d *DB) InsertLog(timestamp time.Time, level, message, email, module string) error {
_, err := d.db.Exec(`
INSERT INTO app_logs (timestamp, level, message, email, module)
VALUES (?, ?, ?, ?, ?)
`, timestamp, level, message, email, module)
return err
}
// GetLogs 获取最近的日志
func (d *DB) GetLogs(limit int) ([]LogEntry, error) {
if limit <= 0 {
limit = 100
}
if limit > 1000 {
limit = 1000
}
rows, err := d.db.Query(`
SELECT id, timestamp, level, message, COALESCE(email, ''), module
FROM app_logs
ORDER BY timestamp DESC
LIMIT ?
`, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var logs []LogEntry
for rows.Next() {
var log LogEntry
if err := rows.Scan(&log.ID, &log.Timestamp, &log.Level, &log.Message, &log.Email, &log.Module); err != nil {
continue
}
logs = append(logs, log)
}
// 反转顺序(让最新的在后面,符合日志显示习惯)
for i, j := 0, len(logs)-1; i < j; i, j = i+1, j-1 {
logs[i], logs[j] = logs[j], logs[i]
}
return logs, nil
}
// GetLogsByModule 按模块获取日志
func (d *DB) GetLogsByModule(module string, page, pageSize int) ([]LogEntry, int, error) {
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
// 获取总数
var total int
d.db.QueryRow("SELECT COUNT(*) FROM app_logs WHERE module = ?", module).Scan(&total)
offset := (page - 1) * pageSize
rows, err := d.db.Query(`
SELECT id, timestamp, level, message, COALESCE(email, ''), module
FROM app_logs
WHERE module = ?
ORDER BY timestamp DESC
LIMIT ? OFFSET ?
`, module, pageSize, offset)
if err != nil {
return nil, 0, err
}
defer rows.Close()
var logs []LogEntry
for rows.Next() {
var log LogEntry
if err := rows.Scan(&log.ID, &log.Timestamp, &log.Level, &log.Message, &log.Email, &log.Module); err != nil {
continue
}
logs = append(logs, log)
}
return logs, total, nil
}
// GetLogsByModuleAndLevel 按模块和级别获取日志
func (d *DB) GetLogsByModuleAndLevel(module, level string, page, pageSize int) ([]LogEntry, int, error) {
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
// 构建查询
countQuery := "SELECT COUNT(*) FROM app_logs WHERE module = ?"
selectQuery := `
SELECT id, timestamp, level, message, COALESCE(email, ''), module
FROM app_logs
WHERE module = ?`
args := []interface{}{module}
if level != "" {
countQuery += " AND level = ?"
selectQuery += " AND level = ?"
args = append(args, level)
}
// 获取总数
var total int
d.db.QueryRow(countQuery, args...).Scan(&total)
offset := (page - 1) * pageSize
selectQuery += " ORDER BY timestamp DESC LIMIT ? OFFSET ?"
args = append(args, pageSize, offset)
rows, err := d.db.Query(selectQuery, args...)
if err != nil {
return nil, 0, err
}
defer rows.Close()
var logs []LogEntry
for rows.Next() {
var log LogEntry
if err := rows.Scan(&log.ID, &log.Timestamp, &log.Level, &log.Message, &log.Email, &log.Module); err != nil {
continue
}
logs = append(logs, log)
}
return logs, total, nil
}
// ClearLogs 清空所有日志
func (d *DB) ClearLogs() error {
_, err := d.db.Exec("DELETE FROM app_logs")
return err
}
// ClearLogsByModule 按模块清空日志
func (d *DB) ClearLogsByModule(module string) (int64, error) {
result, err := d.db.Exec("DELETE FROM app_logs WHERE module = ?", module)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// CleanupOldLogs 清理旧日志(保留最近 N 条)
func (d *DB) CleanupOldLogs(keepCount int) (int64, error) {
if keepCount <= 0 {
keepCount = 5000
}
result, err := d.db.Exec(`
DELETE FROM app_logs
WHERE id NOT IN (
SELECT id FROM app_logs ORDER BY timestamp DESC LIMIT ?
)
`, keepCount)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// Close 关闭数据库
func (d *DB) Close() error {
if d.db != nil {