460 lines
14 KiB
Go
460 lines
14 KiB
Go
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)
|
|
}
|