package controllers import ( "encoding/json" "io" "strconv" "strings" "time" "server/models" "server/pkg/jwtutil" "github.com/beego/beego/v2/client/orm" "github.com/beego/beego/v2/core/logs" beego "github.com/beego/beego/v2/server/web" ) type passwordPayload struct { Platform string `json:"platform"` URL string `json:"url"` Accounts []models.PasswordAccountItem `json:"accounts"` Remark string `json:"remark"` } // PasswordStoreItemDTO 统一返回给前端的结构体,包含解析后的账号列表 type PasswordStoreItemDTO struct { ID uint64 `json:"id"` Tid int `json:"tid,omitempty"` Platform string `json:"platform"` URL string `json:"url"` Accounts []models.PasswordAccountItem `json:"accounts"` Remark string `json:"remark"` UserID uint64 `json:"user_id"` CreateTime time.Time `json:"create_time"` UpdateTime *time.Time `json:"update_time"` } func accountsToJSON(list []models.PasswordAccountItem) string { cleaned := make([]models.PasswordAccountItem, 0, len(list)) for _, item := range list { u := strings.TrimSpace(item.Username) p := strings.TrimSpace(item.Password) reg := strings.TrimSpace(item.RegistrationInfo) rem := strings.TrimSpace(item.Remark) if u == "" && p == "" && reg == "" && rem == "" { continue } cleaned = append(cleaned, models.PasswordAccountItem{ Username: u, Password: p, RegistrationInfo: reg, Remark: rem, }) } b, err := json.Marshal(cleaned) if err != nil { return "[]" } return string(b) } func accountsFromJSON(raw string) []models.PasswordAccountItem { raw = strings.TrimSpace(raw) if raw == "" { return []models.PasswordAccountItem{} } var list []models.PasswordAccountItem if err := json.Unmarshal([]byte(raw), &list); err == nil && list != nil { return list } return []models.PasswordAccountItem{} } func passwordClaims(c *beego.Controller, kind string) (*jwtutil.Claims, error) { p := strings.SplitN(c.Ctx.Request.Header.Get("Authorization"), " ", 2) if len(p) != 2 || p[0] != "Bearer" { return nil, orm.ErrNoRows } cl, e := jwtutil.ParseToken(p[1]) if e != nil || cl.UserType != kind || cl.UserID <= 0 { return nil, orm.ErrNoRows } return cl, nil } func parsePassword(c *beego.Controller) (passwordPayload, error) { var p passwordPayload b, e := io.ReadAll(c.Ctx.Request.Body) if e == nil { e = json.Unmarshal(b, &p) } p.Platform = strings.TrimSpace(p.Platform) p.URL = strings.TrimSpace(p.URL) p.Remark = strings.TrimSpace(p.Remark) return p, e } func passwordReply(c *beego.Controller, status int, msg string, data interface{}) { c.Ctx.Output.SetStatus(status) c.Data["json"] = map[string]interface{}{"code": status, "msg": msg, "data": data} _ = c.ServeJSON() } func validPassword(p passwordPayload) bool { return p.Platform != "" } // ==================== 平台端 Password Store ==================== type PlatformPasswordStoreController struct{ beego.Controller } func (c *PlatformPasswordStoreController) List() { cl, e := passwordClaims(&c.Controller, "platform") if e != nil { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } qs := models.Orm.QueryTable(new(models.PlatformPasswordStore)).Filter("is_deleted", 0).Filter("user_id", cl.UserID) k := strings.TrimSpace(c.GetString("keyword")) if k != "" { cond := orm.NewCondition(). Or("platform__icontains", k). Or("url__icontains", k). Or("accounts__icontains", k). Or("remark__icontains", k) qs = qs.SetCond(orm.NewCondition().And("is_deleted", 0).And("user_id", cl.UserID).AndCond(cond)) } total, _ := qs.Count() var list []models.PlatformPasswordStore _, e = qs.OrderBy("-id").Limit(200).All(&list) if e != nil && e != orm.ErrNoRows { logs.Error("[passwordStore] platform list failed: %v", e) passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) return } res := make([]PasswordStoreItemDTO, 0, len(list)) for _, row := range list { res = append(res, PasswordStoreItemDTO{ ID: row.ID, Platform: row.Platform, URL: row.URL, Accounts: accountsFromJSON(row.Accounts), Remark: row.Remark, UserID: row.UserID, CreateTime: row.CreateTime, UpdateTime: row.UpdateTime, }) } passwordReply(&c.Controller, 200, "success", map[string]interface{}{"list": res, "total": total}) } func (c *PlatformPasswordStoreController) Detail() { cl, e := passwordClaims(&c.Controller, "platform") if e != nil { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) var v models.PlatformPasswordStore e = models.Orm.QueryTable(new(models.PlatformPasswordStore)).Filter("id", id).Filter("is_deleted", 0).Filter("user_id", cl.UserID).One(&v) if e != nil { passwordReply(&c.Controller, 404, "记录不存在", nil) return } dto := PasswordStoreItemDTO{ ID: v.ID, Platform: v.Platform, URL: v.URL, Accounts: accountsFromJSON(v.Accounts), Remark: v.Remark, UserID: v.UserID, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, } passwordReply(&c.Controller, 200, "success", dto) } func (c *PlatformPasswordStoreController) Create() { cl, e := passwordClaims(&c.Controller, "platform") if e != nil { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } p, e := parsePassword(&c.Controller) if e != nil || !validPassword(p) { passwordReply(&c.Controller, 400, "平台名称不能为空", nil) return } accJSON := accountsToJSON(p.Accounts) v := &models.PlatformPasswordStore{ Platform: p.Platform, URL: p.URL, Accounts: accJSON, Remark: p.Remark, UserID: uint64(cl.UserID), } id, e := models.Orm.Insert(v) if e != nil { logs.Error("[passwordStore] platform create failed: %v", e) passwordReply(&c.Controller, 500, "创建失败: "+e.Error(), nil) return } v.ID = uint64(id) dto := PasswordStoreItemDTO{ ID: v.ID, Platform: v.Platform, URL: v.URL, Accounts: accountsFromJSON(v.Accounts), Remark: v.Remark, UserID: v.UserID, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, } passwordReply(&c.Controller, 200, "创建成功", dto) } func (c *PlatformPasswordStoreController) Update() { cl, e := passwordClaims(&c.Controller, "platform") if e != nil { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) p, e := parsePassword(&c.Controller) if e != nil || !validPassword(p) { passwordReply(&c.Controller, 400, "平台名称不能为空", nil) return } var v models.PlatformPasswordStore e = models.Orm.QueryTable(new(models.PlatformPasswordStore)).Filter("id", id).Filter("is_deleted", 0).Filter("user_id", cl.UserID).One(&v) if e != nil { passwordReply(&c.Controller, 404, "记录不存在", nil) return } now := time.Now() accJSON := accountsToJSON(p.Accounts) _, e = models.Orm.QueryTable(new(models.PlatformPasswordStore)).Filter("id", id).Update(map[string]interface{}{ "platform": p.Platform, "url": p.URL, "accounts": accJSON, "remark": p.Remark, "update_time": now, }) if e != nil { logs.Error("[passwordStore] platform update failed: %v", e) passwordReply(&c.Controller, 500, "更新失败: "+e.Error(), nil) return } v.Platform = p.Platform v.URL = p.URL v.Accounts = accJSON v.Remark = p.Remark v.UpdateTime = &now dto := PasswordStoreItemDTO{ ID: v.ID, Platform: v.Platform, URL: v.URL, Accounts: accountsFromJSON(v.Accounts), Remark: v.Remark, UserID: v.UserID, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, } passwordReply(&c.Controller, 200, "更新成功", dto) } func (c *PlatformPasswordStoreController) Delete() { cl, e := passwordClaims(&c.Controller, "platform") if e != nil { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) n, e := models.Orm.QueryTable(new(models.PlatformPasswordStore)).Filter("id", id).Filter("user_id", cl.UserID).Update(map[string]interface{}{"is_deleted": 1, "delete_time": time.Now()}) if e != nil || n == 0 { passwordReply(&c.Controller, 404, "记录不存在", nil) return } passwordReply(&c.Controller, 200, "删除成功", nil) } // ==================== 租户端 Password Store ==================== type BackendPasswordStoreController struct{ beego.Controller } func (c *BackendPasswordStoreController) List() { cl, e := passwordClaims(&c.Controller, "backend") if e != nil || cl.TenantId <= 0 { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } qs := models.Orm.QueryTable(new(models.BackendPasswordStore)).Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID) k := strings.TrimSpace(c.GetString("keyword")) if k != "" { cond := orm.NewCondition(). Or("platform__icontains", k). Or("url__icontains", k). Or("accounts__icontains", k). Or("remark__icontains", k) qs = qs.SetCond(orm.NewCondition().And("is_deleted", 0).And("tid", cl.TenantId).And("user_id", cl.UserID).AndCond(cond)) } total, _ := qs.Count() var list []models.BackendPasswordStore _, e = qs.OrderBy("-id").Limit(200).All(&list) if e != nil && e != orm.ErrNoRows { logs.Error("[passwordStore] backend list failed: %v", e) passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) return } res := make([]PasswordStoreItemDTO, 0, len(list)) for _, row := range list { res = append(res, PasswordStoreItemDTO{ ID: row.ID, Tid: row.Tid, Platform: row.Platform, URL: row.URL, Accounts: accountsFromJSON(row.Accounts), Remark: row.Remark, UserID: row.UserID, CreateTime: row.CreateTime, UpdateTime: row.UpdateTime, }) } passwordReply(&c.Controller, 200, "success", map[string]interface{}{"list": res, "total": total}) } func (c *BackendPasswordStoreController) Detail() { cl, e := passwordClaims(&c.Controller, "backend") if e != nil || cl.TenantId <= 0 { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) var v models.BackendPasswordStore e = models.Orm.QueryTable(new(models.BackendPasswordStore)).Filter("id", id).Filter("tid", cl.TenantId).Filter("is_deleted", 0).Filter("user_id", cl.UserID).One(&v) if e != nil { passwordReply(&c.Controller, 404, "记录不存在", nil) return } dto := PasswordStoreItemDTO{ ID: v.ID, Tid: v.Tid, Platform: v.Platform, URL: v.URL, Accounts: accountsFromJSON(v.Accounts), Remark: v.Remark, UserID: v.UserID, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, } passwordReply(&c.Controller, 200, "success", dto) } func (c *BackendPasswordStoreController) Create() { cl, e := passwordClaims(&c.Controller, "backend") if e != nil || cl.TenantId <= 0 { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } p, e := parsePassword(&c.Controller) if e != nil || !validPassword(p) { passwordReply(&c.Controller, 400, "平台名称不能为空", nil) return } accJSON := accountsToJSON(p.Accounts) v := &models.BackendPasswordStore{ Tid: cl.TenantId, Platform: p.Platform, URL: p.URL, Accounts: accJSON, Remark: p.Remark, UserID: uint64(cl.UserID), } id, e := models.Orm.Insert(v) if e != nil { logs.Error("[passwordStore] backend create failed: %v", e) passwordReply(&c.Controller, 500, "创建失败: "+e.Error(), nil) return } v.ID = uint64(id) dto := PasswordStoreItemDTO{ ID: v.ID, Tid: v.Tid, Platform: v.Platform, URL: v.URL, Accounts: accountsFromJSON(v.Accounts), Remark: v.Remark, UserID: v.UserID, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, } passwordReply(&c.Controller, 200, "创建成功", dto) } func (c *BackendPasswordStoreController) Update() { cl, e := passwordClaims(&c.Controller, "backend") if e != nil || cl.TenantId <= 0 { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) p, e := parsePassword(&c.Controller) if e != nil || !validPassword(p) { passwordReply(&c.Controller, 400, "平台名称不能为空", nil) return } var v models.BackendPasswordStore e = models.Orm.QueryTable(new(models.BackendPasswordStore)).Filter("id", id).Filter("tid", cl.TenantId).Filter("is_deleted", 0).Filter("user_id", cl.UserID).One(&v) if e != nil { passwordReply(&c.Controller, 404, "记录不存在", nil) return } now := time.Now() accJSON := accountsToJSON(p.Accounts) _, e = models.Orm.QueryTable(new(models.BackendPasswordStore)).Filter("id", id).Update(map[string]interface{}{ "platform": p.Platform, "url": p.URL, "accounts": accJSON, "remark": p.Remark, "update_time": now, }) if e != nil { logs.Error("[passwordStore] backend update failed: %v", e) passwordReply(&c.Controller, 500, "更新失败: "+e.Error(), nil) return } v.Platform = p.Platform v.URL = p.URL v.Accounts = accJSON v.Remark = p.Remark v.UpdateTime = &now dto := PasswordStoreItemDTO{ ID: v.ID, Tid: v.Tid, Platform: v.Platform, URL: v.URL, Accounts: accountsFromJSON(v.Accounts), Remark: v.Remark, UserID: v.UserID, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, } passwordReply(&c.Controller, 200, "更新成功", dto) } func (c *BackendPasswordStoreController) Delete() { cl, e := passwordClaims(&c.Controller, "backend") if e != nil || cl.TenantId <= 0 { passwordReply(&c.Controller, 401, "未登录或无权限", nil) return } id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) n, e := models.Orm.QueryTable(new(models.BackendPasswordStore)).Filter("id", id).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID).Update(map[string]interface{}{"is_deleted": 1, "delete_time": time.Now()}) if e != nil || n == 0 { passwordReply(&c.Controller, 404, "记录不存在", nil) return } passwordReply(&c.Controller, 200, "删除成功", nil) }