chore: 代码调整

This commit is contained in:
yokowu
2025-07-23 16:38:59 +08:00
parent 4ea6713f80
commit 9f61e4fe86
8 changed files with 211 additions and 31 deletions

View File

@@ -1,6 +1,6 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
@@ -78,7 +78,7 @@ func newServer() (*Server, error) {
if err != nil {
return nil, err
}
userRepo := repo5.NewUserRepo(client, ipdbIPDB, redisClient)
userRepo := repo5.NewUserRepo(client, ipdbIPDB, redisClient, configConfig)
userUsecase := usecase4.NewUserUsecase(configConfig, redisClient, userRepo, slogLogger, sessionSession)
dashboardRepo := repo6.NewDashboardRepo(client)
dashboardUsecase := usecase5.NewDashboardUsecase(dashboardRepo)

View File

@@ -24,6 +24,7 @@ type Config struct {
Admin struct {
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
Limit int `mapstructure:"limit"`
} `mapstructure:"admin"`
Session struct {
@@ -82,6 +83,7 @@ func Init() (*Config, error) {
v.SetDefault("server.addr", ":8888")
v.SetDefault("admin.user", "admin")
v.SetDefault("admin.password", "")
v.SetDefault("admin.limit", 100)
v.SetDefault("session.expire_day", 30)
v.SetDefault("database.master", "")
v.SetDefault("database.slave", "")

View File

@@ -99,6 +99,46 @@
}
}
},
"/api/v1/admin/export-completion-data": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "管理员导出所有补全相关数据",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "导出补全数据",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/domain.ExportCompletionDataResp"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/web.Resp"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/web.Resp"
}
}
}
}
},
"/api/v1/admin/list": {
"get": {
"description": "获取管理员用户列表",
@@ -3118,6 +3158,92 @@
}
}
},
"domain.CompletionData": {
"type": "object",
"properties": {
"code_lines": {
"description": "代码行数",
"type": "integer"
},
"completion": {
"description": "LLM生成的补全代码",
"type": "string"
},
"created_at": {
"description": "创建时间戳",
"type": "integer"
},
"cursor_position": {
"description": "光标位置 {\"line\": 10, \"column\": 5}",
"type": "object",
"additionalProperties": {}
},
"input_tokens": {
"description": "输入token数",
"type": "integer"
},
"is_accept": {
"description": "用户是否接受补全",
"type": "boolean"
},
"is_suggested": {
"description": "是否为建议模式",
"type": "boolean"
},
"model_id": {
"description": "模型ID",
"type": "string"
},
"model_name": {
"description": "模型名称",
"type": "string"
},
"model_type": {
"description": "模型类型",
"type": "string"
},
"output_tokens": {
"description": "输出token数",
"type": "integer"
},
"program_language": {
"description": "编程语言",
"type": "string"
},
"prompt": {
"description": "用户输入的提示",
"type": "string"
},
"request_id": {
"description": "请求ID",
"type": "string"
},
"source_code": {
"description": "当前文件原文",
"type": "string"
},
"task_id": {
"description": "任务ID",
"type": "string"
},
"updated_at": {
"description": "更新时间戳",
"type": "integer"
},
"user_id": {
"description": "用户ID",
"type": "string"
},
"user_input": {
"description": "用户最终输入的内容",
"type": "string"
},
"work_mode": {
"description": "工作模式",
"type": "string"
}
}
},
"domain.CompletionInfo": {
"type": "object",
"properties": {
@@ -3384,6 +3510,22 @@
}
}
},
"domain.ExportCompletionDataResp": {
"type": "object",
"properties": {
"data": {
"description": "补全数据列表",
"type": "array",
"items": {
"$ref": "#/definitions/domain.CompletionData"
}
},
"total_count": {
"description": "总记录数",
"type": "integer"
}
}
},
"domain.GetProviderModelListResp": {
"type": "object",
"properties": {
@@ -3895,7 +4037,8 @@
},
"cursor_position": {
"description": "光标位置用于reject action",
"type": "integer"
"type": "object",
"additionalProperties": {}
},
"id": {
"description": "task_id or resp_id",

View File

@@ -40,14 +40,7 @@ type StatisticsFilter struct {
}
func (s StatisticsFilter) StartTime() time.Time {
switch s.Precision {
case "hour":
return time.Now().Add(-time.Duration(s.Duration) * time.Hour)
case "day":
return time.Now().AddDate(0, 0, -int(s.Duration))
default:
return time.Now().AddDate(0, 0, -90)
}
return time.Now().Add(-24 * time.Hour)
}
type UserHeatmapResp struct {

View File

@@ -20,4 +20,5 @@ var (
ErrNotInvited = web.NewBadRequestErr("err-not-invited")
ErrDingtalkNotEnabled = web.NewBadRequestErr("err-dingtalk-not-enabled")
ErrCustomNotEnabled = web.NewBadRequestErr("err-custom-not-enabled")
ErrUserLimit = web.NewBadRequestErr("err-user-limit")
)

View File

@@ -26,4 +26,7 @@ other = "未被邀请"
other = "钉钉未启用"
[err-custom-not-enabled]
other = "OAuth未启用"
other = "OAuth未启用"
[err-user-limit]
other = "用户数量已达上限"

View File

@@ -623,16 +623,17 @@ func (h *UserHandler) InitAdmin() error {
}
// ExportCompletionData godoc
// @Summary 导出补全数据
// @Description 管理员导出所有补全相关数据
// @Tags admin
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Success 200 {object} domain.ExportCompletionDataResp
// @Failure 401 {object} errcode.Error
// @Failure 500 {object} errcode.Error
// @Router /api/v1/admin/export-completion-data [get]
//
// @Summary 导出补全数据
// @Description 管理员导出所有补全相关数据
// @Tags admin
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Success 200 {object} domain.ExportCompletionDataResp
// @Failure 401 {object} web.Resp{}
// @Failure 500 {object} web.Resp{}
// @Router /api/v1/admin/export-completion-data [get]
func (h *UserHandler) ExportCompletionData(c *web.Context) error {
data, err := h.usecase.ExportCompletionData(c.Request().Context())
if err != nil {

View File

@@ -12,6 +12,7 @@ import (
"github.com/GoYoko/web"
"github.com/chaitin/MonkeyCode/backend/config"
"github.com/chaitin/MonkeyCode/backend/consts"
"github.com/chaitin/MonkeyCode/backend/db"
"github.com/chaitin/MonkeyCode/backend/db/admin"
@@ -32,10 +33,16 @@ type UserRepo struct {
db *db.Client
ipdb *ipdb.IPDB
redis *redis.Client
cfg *config.Config
}
func NewUserRepo(db *db.Client, ipdb *ipdb.IPDB, redis *redis.Client) domain.UserRepo {
return &UserRepo{db: db, ipdb: ipdb, redis: redis}
func NewUserRepo(
db *db.Client,
ipdb *ipdb.IPDB,
redis *redis.Client,
cfg *config.Config,
) domain.UserRepo {
return &UserRepo{db: db, ipdb: ipdb, redis: redis, cfg: cfg}
}
func (r *UserRepo) InitAdmin(ctx context.Context, username, password string) error {
@@ -113,13 +120,25 @@ func (r *UserRepo) innerValidateInviteCode(ctx context.Context, tx *db.Tx, code
}
func (r *UserRepo) CreateUser(ctx context.Context, user *db.User) (*db.User, error) {
return r.db.User.Create().
SetUsername(user.Username).
SetEmail(user.Email).
SetPassword(user.Password).
SetStatus(user.Status).
SetPlatform(user.Platform).
Save(ctx)
var res *db.User
err := entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
if err := r.checkLimit(ctx, tx); err != nil {
return err
}
u, err := tx.User.Create().
SetUsername(user.Username).
SetEmail(user.Email).
SetPassword(user.Password).
SetStatus(user.Status).
SetPlatform(user.Platform).
Save(ctx)
if err != nil {
return err
}
res = u
return nil
})
return res, err
}
func (r *UserRepo) UserLoginHistory(ctx context.Context, page *web.Pagination) ([]*db.UserLoginHistory, *db.PageInfo, error) {
@@ -297,6 +316,10 @@ func (r *UserRepo) DeleteAdmin(ctx context.Context, id string) error {
func (r *UserRepo) OAuthRegister(ctx context.Context, platform consts.UserPlatform, inviteCode string, req *domain.OAuthUserInfo) (*db.User, error) {
var u *db.User
err := entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
if err := r.checkLimit(ctx, tx); err != nil {
return err
}
if _, err := r.innerValidateInviteCode(ctx, tx, inviteCode); err != nil {
return errcode.ErrInviteCodeInvalid.Wrap(err)
}
@@ -365,6 +388,17 @@ func (r *UserRepo) updateAvatar(ctx context.Context, tx *db.Tx, ui *db.UserIdent
return tx.User.UpdateOneID(ui.UserID).SetAvatarURL(avatar).Exec(ctx)
}
func (r *UserRepo) checkLimit(ctx context.Context, tx *db.Tx) error {
count, err := tx.User.Query().Count(ctx)
if err != nil {
return err
}
if count >= r.cfg.Admin.Limit {
return errcode.ErrUserLimit.Wrap(err)
}
return nil
}
func (r *UserRepo) SignUpOrIn(ctx context.Context, platform consts.UserPlatform, req *domain.OAuthUserInfo) (*db.User, error) {
var u *db.User
err := entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
@@ -384,6 +418,9 @@ func (r *UserRepo) SignUpOrIn(ctx context.Context, platform consts.UserPlatform,
if !db.IsNotFound(err) {
return err
}
if err = r.checkLimit(ctx, tx); err != nil {
return err
}
user, err := tx.User.Create().
SetUsername(req.Name).
SetEmail(req.Email).