225 lines
6.4 KiB
Go
225 lines
6.4 KiB
Go
package controllers
|
||
|
||
import (
|
||
"encoding/json"
|
||
"strings"
|
||
"time"
|
||
|
||
"server/models"
|
||
|
||
"github.com/beego/beego/v2/client/orm"
|
||
beego "github.com/beego/beego/v2/server/web"
|
||
)
|
||
|
||
// ApiCursorEquipmentController 开放接口:登录器上报 Cursor 设备信息(无需登录)
|
||
type ApiCursorEquipmentController struct {
|
||
beego.Controller
|
||
}
|
||
|
||
type cursorEquipmentReportPayload struct {
|
||
DeviceInfo string `json:"deviceInfo"`
|
||
DeviceInfoSnake string `json:"device_info"`
|
||
MachineCode string `json:"machineCode"`
|
||
MachineCodeSnake string `json:"machine_code"`
|
||
Status *int8 `json:"status"`
|
||
System string `json:"system"`
|
||
Version string `json:"version"`
|
||
BindAccount string `json:"bindAccount"`
|
||
BindAccountSnake string `json:"bind_account"`
|
||
OwnerUserID *uint64 `json:"ownerUserId"`
|
||
OwnerUserIDSnake *uint64 `json:"owner_user_id"`
|
||
OwnerUserName string `json:"ownerUserName"`
|
||
OwnerUserNameSnake string `json:"owner_user_name"`
|
||
ActivationTime string `json:"activationTime"`
|
||
ActivationTimeSnake string `json:"activation_time"`
|
||
ExpireTime string `json:"expireTime"`
|
||
ExpireTimeSnake string `json:"expire_time"`
|
||
Remark string `json:"remark"`
|
||
}
|
||
|
||
func cursorFirstNonEmpty(values ...string) string {
|
||
for _, v := range values {
|
||
if s := strings.TrimSpace(v); s != "" {
|
||
return s
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func cursorStringPtr(value string) *string {
|
||
value = strings.TrimSpace(value)
|
||
if value == "" {
|
||
return nil
|
||
}
|
||
return &value
|
||
}
|
||
|
||
func cursorParseTimePtr(value string) *time.Time {
|
||
value = strings.TrimSpace(value)
|
||
if value == "" {
|
||
return nil
|
||
}
|
||
|
||
layouts := []string{
|
||
time.RFC3339,
|
||
"2006-01-02 15:04:05",
|
||
"2006-01-02 15:04",
|
||
"2006-01-02",
|
||
}
|
||
for _, layout := range layouts {
|
||
if t, err := time.ParseInLocation(layout, value, time.Local); err == nil {
|
||
return &t
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func cursorValidStatus(status int8) bool {
|
||
return status == 0 || status == 1 || status == 2 || status == 3
|
||
}
|
||
|
||
func (c *ApiCursorEquipmentController) jsonResult(code int, msg string, data interface{}) {
|
||
resp := map[string]interface{}{"code": code, "msg": msg}
|
||
if data != nil {
|
||
resp["data"] = data
|
||
}
|
||
c.Data["json"] = resp
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// Report POST /api/cursor/equipment/report
|
||
//
|
||
// JSON 示例:
|
||
//
|
||
// {
|
||
// "machineCode": "ABC-123",
|
||
// "deviceInfo": "CPU/RAM/磁盘等设备信息",
|
||
// "system": "Windows",
|
||
// "version": "1.0.0",
|
||
// "bindAccount": "user@example.com",
|
||
// "ownerUserId": 1,
|
||
// "ownerUserName": "张三",
|
||
// "activationTime": "2026-06-15 22:00:00",
|
||
// "expireTime": "2026-07-15 22:00:00",
|
||
// "remark": "登录器上报"
|
||
// }
|
||
//
|
||
// 兼容 snake_case 字段,例如 machine_code、device_info、bind_account。
|
||
func (c *ApiCursorEquipmentController) Report() {
|
||
var p cursorEquipmentReportPayload
|
||
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &p); err != nil {
|
||
c.jsonResult(400, "参数错误", nil)
|
||
return
|
||
}
|
||
|
||
machineCode := cursorFirstNonEmpty(p.MachineCode, p.MachineCodeSnake)
|
||
if machineCode == "" {
|
||
c.jsonResult(400, "缺少参数 machineCode/machine_code(机器码)", nil)
|
||
return
|
||
}
|
||
if len(machineCode) > 128 {
|
||
c.jsonResult(400, "机器码长度不能超过 128 个字符", nil)
|
||
return
|
||
}
|
||
|
||
status := int8(0)
|
||
statusProvided := p.Status != nil
|
||
if statusProvided {
|
||
status = *p.Status
|
||
if !cursorValidStatus(status) {
|
||
c.jsonResult(400, "状态不合法,支持:0 未激活、1 激活中、2 已过期、3 已禁用", nil)
|
||
return
|
||
}
|
||
}
|
||
|
||
deviceInfo := cursorFirstNonEmpty(p.DeviceInfo, p.DeviceInfoSnake)
|
||
system := cursorFirstNonEmpty(p.System)
|
||
version := cursorFirstNonEmpty(p.Version)
|
||
bindAccount := cursorFirstNonEmpty(p.BindAccount, p.BindAccountSnake)
|
||
ownerUserID := p.OwnerUserID
|
||
if ownerUserID == nil {
|
||
ownerUserID = p.OwnerUserIDSnake
|
||
}
|
||
ownerUserName := cursorFirstNonEmpty(p.OwnerUserName, p.OwnerUserNameSnake)
|
||
activationTime := cursorParseTimePtr(cursorFirstNonEmpty(p.ActivationTime, p.ActivationTimeSnake))
|
||
expireTime := cursorParseTimePtr(cursorFirstNonEmpty(p.ExpireTime, p.ExpireTimeSnake))
|
||
remark := cursorFirstNonEmpty(p.Remark)
|
||
|
||
now := time.Now()
|
||
var row models.PlatformCursorEquipment
|
||
err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
|
||
Filter("machine_code", machineCode).
|
||
Filter("delete_time__isnull", true).
|
||
One(&row)
|
||
|
||
created := false
|
||
if err == orm.ErrNoRows {
|
||
row = models.PlatformCursorEquipment{
|
||
MachineCode: machineCode,
|
||
Status: status,
|
||
DeviceInfo: cursorStringPtr(deviceInfo),
|
||
System: cursorStringPtr(system),
|
||
Version: cursorStringPtr(version),
|
||
BindAccount: cursorStringPtr(bindAccount),
|
||
OwnerUserID: ownerUserID,
|
||
OwnerUserName: cursorStringPtr(ownerUserName),
|
||
ActivationTime: activationTime,
|
||
ExpireTime: expireTime,
|
||
Remark: cursorStringPtr(remark),
|
||
CreateTime: now,
|
||
}
|
||
id, insertErr := models.Orm.Insert(&row)
|
||
if insertErr != nil {
|
||
c.jsonResult(500, "设备信息保存失败", nil)
|
||
return
|
||
}
|
||
row.ID = uint64(id)
|
||
created = true
|
||
} else if err != nil {
|
||
c.jsonResult(500, "设备信息查询失败", nil)
|
||
return
|
||
} else {
|
||
update := map[string]interface{}{
|
||
"device_info": cursorStringPtr(deviceInfo),
|
||
"system": cursorStringPtr(system),
|
||
"version": cursorStringPtr(version),
|
||
"bind_account": cursorStringPtr(bindAccount),
|
||
"owner_user_id": ownerUserID,
|
||
"owner_user_name": cursorStringPtr(ownerUserName),
|
||
"activation_time": activationTime,
|
||
"expire_time": expireTime,
|
||
"remark": cursorStringPtr(remark),
|
||
"update_time": now,
|
||
}
|
||
if statusProvided {
|
||
update["status"] = status
|
||
row.Status = status
|
||
}
|
||
|
||
if _, updateErr := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
|
||
Filter("id", row.ID).
|
||
Update(update); updateErr != nil {
|
||
c.jsonResult(500, "设备信息更新失败", nil)
|
||
return
|
||
}
|
||
|
||
row.DeviceInfo = cursorStringPtr(deviceInfo)
|
||
row.System = cursorStringPtr(system)
|
||
row.Version = cursorStringPtr(version)
|
||
row.BindAccount = cursorStringPtr(bindAccount)
|
||
row.OwnerUserID = ownerUserID
|
||
row.OwnerUserName = cursorStringPtr(ownerUserName)
|
||
row.ActivationTime = activationTime
|
||
row.ExpireTime = expireTime
|
||
row.Remark = cursorStringPtr(remark)
|
||
row.UpdateTime = &now
|
||
}
|
||
|
||
c.jsonResult(200, "success", map[string]interface{}{
|
||
"id": row.ID,
|
||
"machineCode": row.MachineCode,
|
||
"status": row.Status,
|
||
"created": created,
|
||
})
|
||
}
|