reface to openteam
This commit is contained in:
6
internal/dto/batch.go
Normal file
6
internal/dto/batch.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package dto
|
||||
|
||||
type BatchIDRequest struct {
|
||||
UserID *int64 `json:"user_id"`
|
||||
IDs []int64 `json:"ids" binding:"required"`
|
||||
}
|
||||
20
internal/dto/error.go
Normal file
20
internal/dto/error.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
Code int `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func WrapErrorAsOpenAI(c *gin.Context, code int, msg string) {
|
||||
c.JSON(code, gin.H{
|
||||
"error": Error{
|
||||
Code: code,
|
||||
Message: msg,
|
||||
},
|
||||
})
|
||||
c.Abort()
|
||||
}
|
||||
107
internal/dto/key.go
Normal file
107
internal/dto/key.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||
)
|
||||
|
||||
// TeamKey 结构体定义
|
||||
type TeamKey struct {
|
||||
ID *int64 `json:"id,omitempty"`
|
||||
UserID *int64 `json:"userID,omitempty"`
|
||||
Name *string `json:"name,omitempty"` // 必须
|
||||
Key *string `json:"key,omitempty"`
|
||||
Status *int64 `json:"status,omitempty"` // 默认1 允许,0禁止
|
||||
Quota *int64 `json:"quota,omitempty"` // UnlimitedQuota不为1 的时候必须
|
||||
UnlimitedQuota *bool `json:"unlimitedQuota,omitempty"` // 默认1 不限制,0限制
|
||||
UsedQuota *int64 `json:"usedQuota,omitempty"`
|
||||
CreatedAt *int64 `json:"createdAt,omitempty"`
|
||||
ExpiredAt *int64 `json:"expiredAt,omitempty"` // 可选
|
||||
}
|
||||
|
||||
// DefaultTeamKey 创建一个具有默认值的 TeamKey
|
||||
func DefaultTeamKey() TeamKey {
|
||||
status := int64(1) // 默认允许
|
||||
unlimitedQuota := true // 默认不限制
|
||||
createdAt := time.Now().Unix()
|
||||
|
||||
return TeamKey{
|
||||
Status: &status,
|
||||
UnlimitedQuota: &unlimitedQuota,
|
||||
CreatedAt: &createdAt,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate 验证 TeamKey 结构体
|
||||
func (t TeamKey) Validate() error {
|
||||
// 自定义验证规则
|
||||
var quotaRule validation.Rule = validation.Skip
|
||||
if t.UnlimitedQuota != nil && !*t.UnlimitedQuota {
|
||||
quotaRule = validation.Required.Error("当 UnlimitedQuota 为 false 时,Quota 是必填项")
|
||||
}
|
||||
|
||||
// 过期时间校验
|
||||
var expiredAtRule validation.Rule = validation.Skip
|
||||
if t.ExpiredAt != nil {
|
||||
expiredAtRule = validation.Min(time.Now().Unix()).Error("过期时间不能早于当前时间")
|
||||
}
|
||||
|
||||
return validation.ValidateStruct(&t,
|
||||
// ID 通常由系统生成,不需要验证
|
||||
|
||||
// UserID 可选,但如果提供必须大于 0
|
||||
validation.Field(&t.UserID,
|
||||
validation.When(t.UserID != nil, validation.Min(int64(1)).Error("用户 ID 必须大于 0"))),
|
||||
|
||||
// Name 是必填字段
|
||||
validation.Field(&t.Name,
|
||||
validation.Required.Error("名称不能为空"),
|
||||
validation.When(t.Name != nil, validation.Length(1, 100).Error("名称长度应在 1-100 之间"))),
|
||||
|
||||
// Key 可选,但如果提供需要符合特定格式
|
||||
validation.Field(&t.Key,
|
||||
validation.When(t.Key != nil,
|
||||
validation.Length(1, 255).Error("Key 长度应在 1-255 之间")),
|
||||
validation.Match(regexp.MustCompile(`^[^\s]+$`)).Error("Key 不能包含空格"),
|
||||
),
|
||||
|
||||
// Status 只能是 0 或 1
|
||||
validation.Field(&t.Status,
|
||||
validation.When(t.Status != nil, validation.In(int64(0), int64(1)).Error("状态只能是 0(禁止) 或 1(允许)"))),
|
||||
|
||||
// Quota 要求依赖于 UnlimitedQuota
|
||||
validation.Field(&t.Quota, quotaRule,
|
||||
validation.When(t.Quota != nil, validation.Min(int64(1)).Error("配额必须大于 0"))),
|
||||
|
||||
// UnlimitedQuota 是否限制配额
|
||||
validation.Field(&t.UnlimitedQuota),
|
||||
|
||||
// UsedQuota 系统维护,不需要验证
|
||||
validation.Field(&t.UsedQuota,
|
||||
validation.When(t.UsedQuota != nil, validation.Min(int64(0)).Error("已使用配额不能为负数"))),
|
||||
|
||||
// CreatedAt 系统维护,不需要验证
|
||||
validation.Field(&t.CreatedAt),
|
||||
|
||||
// ExpiredAt 可选,但如果提供必须大于当前时间
|
||||
validation.Field(&t.ExpiredAt, expiredAtRule),
|
||||
)
|
||||
}
|
||||
|
||||
// ValidateCreate 创建时的特殊验证
|
||||
func (t TeamKey) ValidateCreate() error {
|
||||
// 首先进行基本验证
|
||||
if err := t.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建时的额外验证
|
||||
if t.Name == nil {
|
||||
return errors.New("创建时必须提供名称")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
11
internal/dto/passkey.go
Normal file
11
internal/dto/passkey.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package dto
|
||||
|
||||
type Passkey struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
Name string `json:"name" gorm:"column:name"` // 凭证名称,用于用户识别不同的设备
|
||||
SignCount uint32 `json:"sign_count" gorm:"column:sign_count"` // 签名计数器,用于防止重放攻击
|
||||
DeviceType string `json:"device_type" gorm:"column:device_type"` // 设备类型,如"platform"或"cross-platform"
|
||||
LastUsedAt int64 `json:"last_used_at" gorm:"column:last_used_at"` // 最后使用时间
|
||||
CreatedAt int64 `json:"created_at,omitempty" gorm:"autoCreateTime"`
|
||||
UpdatedAt int64 `json:"updated_at,omitempty" gorm:"autoUpdateTime"`
|
||||
}
|
||||
28
internal/dto/response.go
Normal file
28
internal/dto/response.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data any `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func Success(ctx *gin.Context, data any) {
|
||||
ctx.JSON(http.StatusOK, Result{
|
||||
Code: 200,
|
||||
Data: data,
|
||||
Msg: "success",
|
||||
})
|
||||
}
|
||||
|
||||
func Fail(c *gin.Context, code int, err string) {
|
||||
c.AbortWithStatusJSON(code, gin.H{
|
||||
"code": code,
|
||||
"error": err,
|
||||
})
|
||||
}
|
||||
83
internal/dto/team/team.go
Normal file
83
internal/dto/team/team.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"opencatd-open/internal/model"
|
||||
"opencatd-open/internal/utils"
|
||||
)
|
||||
|
||||
type UserInfo struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token"`
|
||||
Status *bool `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (u UserInfo) HasNameUpdate() bool {
|
||||
return u.Name != ""
|
||||
}
|
||||
|
||||
func (u UserInfo) HasTokenUpdate() bool {
|
||||
return u.Token != ""
|
||||
}
|
||||
|
||||
func (u UserInfo) HasStatusUpdate() bool {
|
||||
return u.Status != nil
|
||||
}
|
||||
|
||||
type ApiKeyInfo struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ApiType string `json:"api_type,omitempty"`
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
Status *bool `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// 添加辅助方法判断字段是否需要更新
|
||||
func (k ApiKeyInfo) HasNameUpdate() bool {
|
||||
return k.Name != ""
|
||||
}
|
||||
|
||||
func (k ApiKeyInfo) HasKeyUpdate() bool {
|
||||
return k.Key != ""
|
||||
}
|
||||
|
||||
func (k ApiKeyInfo) HasStatusUpdate() bool {
|
||||
return k.Status != nil
|
||||
}
|
||||
|
||||
func (k ApiKeyInfo) HasApiTypeUpdate() bool {
|
||||
return k.ApiType != ""
|
||||
}
|
||||
|
||||
// 辅助函数:统一处理字段更新
|
||||
func (update *ApiKeyInfo) UpdateFields(existing *model.ApiKey) *model.ApiKey {
|
||||
result := &model.ApiKey{
|
||||
ID: existing.ID,
|
||||
Name: existing.Name, // 默认保持原值
|
||||
ApiType: existing.ApiType, // 默认保持原值
|
||||
ApiKey: existing.ApiKey, // 默认保持原值
|
||||
Active: existing.Active, // 默认保持原值
|
||||
}
|
||||
|
||||
if update.HasNameUpdate() {
|
||||
result.Name = utils.ToPtr(update.Name)
|
||||
}
|
||||
if update.HasKeyUpdate() {
|
||||
result.ApiKey = utils.ToPtr(update.Key)
|
||||
}
|
||||
if update.HasStatusUpdate() {
|
||||
result.Active = update.Status
|
||||
}
|
||||
if update.HasApiTypeUpdate() {
|
||||
result.ApiType = utils.ToPtr(update.ApiType)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type UsageInfo struct {
|
||||
UserId int `json:"userId"`
|
||||
TotalUnit int `json:"totalUnit"`
|
||||
Cost string `json:"cost"`
|
||||
}
|
||||
16
internal/dto/user.go
Normal file
16
internal/dto/user.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package dto
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username" binding:"required,min=3,max=32"`
|
||||
Password string `json:"password" binding:"required,min=4"`
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresIn int64 `json:"expires_in"`
|
||||
}
|
||||
|
||||
type ChangePassword struct {
|
||||
Password string `json:"password" binding:"required,min=4"`
|
||||
NewPassword string `json:"newpassword" binding:"required,min=4"`
|
||||
}
|
||||
Reference in New Issue
Block a user