feat: implement ChatGPT owner demotion service with a FastAPI backend and a basic frontend, alongside updated project metadata.
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user