backend增加租户简称登录
This commit is contained in:
@@ -78,7 +78,7 @@ func (c *BackendNotebookController) List() {
|
||||
total, _ := qs.Count()
|
||||
|
||||
var list []models.BackendNotebook
|
||||
_, err = qs.OrderBy("-update_time", "-create_time").
|
||||
_, err = qs.OrderBy("-pinned", "-id").
|
||||
Limit(pageSize).Offset((page - 1) * pageSize).
|
||||
All(&list)
|
||||
if err != nil && err != orm.ErrNoRows {
|
||||
@@ -137,6 +137,7 @@ func (c *BackendNotebookController) Create() {
|
||||
var payload struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Pinned int8 `json:"pinned"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
c.nbJsonErr(400, 400, "参数错误")
|
||||
@@ -153,6 +154,7 @@ func (c *BackendNotebookController) Create() {
|
||||
Tid: claims.TenantId,
|
||||
Title: payload.Title,
|
||||
Content: payload.Content,
|
||||
Pinned: payload.Pinned,
|
||||
UserID: &userID,
|
||||
UserName: &claims.Username,
|
||||
IsDeleted: 0,
|
||||
@@ -190,6 +192,7 @@ func (c *BackendNotebookController) Update() {
|
||||
var payload struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Pinned int8 `json:"pinned"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
c.nbJsonErr(400, 400, "参数错误")
|
||||
@@ -219,6 +222,7 @@ func (c *BackendNotebookController) Update() {
|
||||
Update(map[string]interface{}{
|
||||
"title": payload.Title,
|
||||
"content": payload.Content,
|
||||
"pinned": payload.Pinned,
|
||||
"update_time": now,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -228,6 +232,7 @@ func (c *BackendNotebookController) Update() {
|
||||
|
||||
note.Title = payload.Title
|
||||
note.Content = payload.Content
|
||||
note.Pinned = payload.Pinned
|
||||
note.UpdateTime = &now
|
||||
c.nbOk(note)
|
||||
}
|
||||
|
||||
+317
-312
@@ -1,312 +1,317 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type PlatformNotebookController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// requireAuth 验证平台用户权限
|
||||
func requireNotebookAuth(c *beego.Controller) (*jwtutil.Claims, error) {
|
||||
auth := c.Ctx.Request.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
parts := strings.SplitN(auth, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if claims.UserType != "platform" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// jsonResponse 统一JSON响应
|
||||
func jsonResponse(c *beego.Controller, httpStatus, code int, msg string, data interface{}) {
|
||||
c.Ctx.Output.SetStatus(httpStatus)
|
||||
resp := map[string]interface{}{
|
||||
"code": code,
|
||||
"msg": msg,
|
||||
}
|
||||
if data != nil {
|
||||
resp["data"] = data
|
||||
}
|
||||
c.Data["json"] = resp
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// List 获取笔记列表
|
||||
// GET /platform/notebook/list
|
||||
func (c *PlatformNotebookController) List() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
page, _ := c.GetInt("page", 1)
|
||||
pageSize, _ := c.GetInt("pageSize", 20)
|
||||
keyword := strings.TrimSpace(c.GetString("keyword"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID)
|
||||
|
||||
if keyword != "" {
|
||||
qs = qs.Filter("title__icontains", keyword)
|
||||
}
|
||||
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var list []models.PlatformNotebook
|
||||
_, err = qs.OrderBy("-update_time", "-create_time").
|
||||
Limit(pageSize).
|
||||
Offset((page - 1) * pageSize).
|
||||
All(&list)
|
||||
|
||||
if err != nil && err != orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if list == nil {
|
||||
list = []models.PlatformNotebook{}
|
||||
}
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "success", map[string]interface{}{
|
||||
"list": list,
|
||||
"total": total,
|
||||
})
|
||||
}
|
||||
|
||||
// Detail 获取笔记详情
|
||||
// GET /platform/notebook/detail/:id
|
||||
func (c *PlatformNotebookController) Detail() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonResponse(&c.Controller, 400, 400, "无效ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var note models.PlatformNotebook
|
||||
err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID).
|
||||
One(¬e)
|
||||
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 404, 404, "笔记不存在", nil)
|
||||
} else {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "success", note)
|
||||
}
|
||||
|
||||
// Create 创建笔记
|
||||
// POST /platform/notebook/create
|
||||
func (c *PlatformNotebookController) Create() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
payload.Title = strings.TrimSpace(payload.Title)
|
||||
if payload.Title == "" {
|
||||
payload.Title = "无标题"
|
||||
}
|
||||
|
||||
userID := uint64(claims.UserID)
|
||||
note := &models.PlatformNotebook{
|
||||
Title: payload.Title,
|
||||
Content: payload.Content,
|
||||
UserID: &userID,
|
||||
UserName: &claims.Username,
|
||||
IsDeleted: 0,
|
||||
}
|
||||
|
||||
id, err := models.Orm.Insert(note)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "创建失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
note.ID = uint64(id)
|
||||
jsonResponse(&c.Controller, 200, 200, "创建成功", note)
|
||||
}
|
||||
|
||||
// Update 更新笔记
|
||||
// POST /platform/notebook/update/:id
|
||||
func (c *PlatformNotebookController) Update() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonResponse(&c.Controller, 400, 400, "无效ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
payload.Title = strings.TrimSpace(payload.Title)
|
||||
if payload.Title == "" {
|
||||
payload.Title = "无标题"
|
||||
}
|
||||
|
||||
// 验证笔记是否存在且属于当前用户
|
||||
var note models.PlatformNotebook
|
||||
err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID).
|
||||
One(¬e)
|
||||
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 404, 404, "笔记不存在", nil)
|
||||
} else {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Update(map[string]interface{}{
|
||||
"title": payload.Title,
|
||||
"content": payload.Content,
|
||||
"update_time": now,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "更新失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
note.Title = payload.Title
|
||||
note.Content = payload.Content
|
||||
note.UpdateTime = &now
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "更新成功", note)
|
||||
}
|
||||
|
||||
// Delete 删除笔记(软删除)
|
||||
// DELETE /platform/notebook/delete/:id
|
||||
func (c *PlatformNotebookController) Delete() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonResponse(&c.Controller, 400, 400, "无效ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证笔记是否存在且属于当前用户
|
||||
var note models.PlatformNotebook
|
||||
err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID).
|
||||
One(¬e)
|
||||
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 404, 404, "笔记不存在", nil)
|
||||
} else {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Update(map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"delete_time": now,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "删除失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "删除成功", nil)
|
||||
}
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type PlatformNotebookController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// requireAuth 验证平台用户权限
|
||||
func requireNotebookAuth(c *beego.Controller) (*jwtutil.Claims, error) {
|
||||
auth := c.Ctx.Request.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
parts := strings.SplitN(auth, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if claims.UserType != "platform" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// jsonResponse 统一JSON响应
|
||||
func jsonResponse(c *beego.Controller, httpStatus, code int, msg string, data interface{}) {
|
||||
c.Ctx.Output.SetStatus(httpStatus)
|
||||
resp := map[string]interface{}{
|
||||
"code": code,
|
||||
"msg": msg,
|
||||
}
|
||||
if data != nil {
|
||||
resp["data"] = data
|
||||
}
|
||||
c.Data["json"] = resp
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// List 获取笔记列表
|
||||
// GET /platform/notebook/list
|
||||
func (c *PlatformNotebookController) List() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
page, _ := c.GetInt("page", 1)
|
||||
pageSize, _ := c.GetInt("pageSize", 20)
|
||||
keyword := strings.TrimSpace(c.GetString("keyword"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID)
|
||||
|
||||
if keyword != "" {
|
||||
qs = qs.Filter("title__icontains", keyword)
|
||||
}
|
||||
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var list []models.PlatformNotebook
|
||||
_, err = qs.OrderBy("-pinned", "-id").
|
||||
Limit(pageSize).
|
||||
Offset((page - 1) * pageSize).
|
||||
All(&list)
|
||||
|
||||
if err != nil && err != orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if list == nil {
|
||||
list = []models.PlatformNotebook{}
|
||||
}
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "success", map[string]interface{}{
|
||||
"list": list,
|
||||
"total": total,
|
||||
})
|
||||
}
|
||||
|
||||
// Detail 获取笔记详情
|
||||
// GET /platform/notebook/detail/:id
|
||||
func (c *PlatformNotebookController) Detail() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonResponse(&c.Controller, 400, 400, "无效ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var note models.PlatformNotebook
|
||||
err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID).
|
||||
One(¬e)
|
||||
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 404, 404, "笔记不存在", nil)
|
||||
} else {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "success", note)
|
||||
}
|
||||
|
||||
// Create 创建笔记
|
||||
// POST /platform/notebook/create
|
||||
func (c *PlatformNotebookController) Create() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Pinned int8 `json:"pinned"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
payload.Title = strings.TrimSpace(payload.Title)
|
||||
if payload.Title == "" {
|
||||
payload.Title = "无标题"
|
||||
}
|
||||
|
||||
userID := uint64(claims.UserID)
|
||||
note := &models.PlatformNotebook{
|
||||
Title: payload.Title,
|
||||
Content: payload.Content,
|
||||
Pinned: payload.Pinned,
|
||||
UserID: &userID,
|
||||
UserName: &claims.Username,
|
||||
IsDeleted: 0,
|
||||
}
|
||||
|
||||
id, err := models.Orm.Insert(note)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "创建失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
note.ID = uint64(id)
|
||||
jsonResponse(&c.Controller, 200, 200, "创建成功", note)
|
||||
}
|
||||
|
||||
// Update 更新笔记
|
||||
// POST /platform/notebook/update/:id
|
||||
func (c *PlatformNotebookController) Update() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonResponse(&c.Controller, 400, 400, "无效ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Pinned int8 `json:"pinned"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
jsonResponse(&c.Controller, 400, 400, "参数错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
payload.Title = strings.TrimSpace(payload.Title)
|
||||
if payload.Title == "" {
|
||||
payload.Title = "无标题"
|
||||
}
|
||||
|
||||
// 验证笔记是否存在且属于当前用户
|
||||
var note models.PlatformNotebook
|
||||
err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID).
|
||||
One(¬e)
|
||||
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 404, 404, "笔记不存在", nil)
|
||||
} else {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Update(map[string]interface{}{
|
||||
"title": payload.Title,
|
||||
"content": payload.Content,
|
||||
"pinned": payload.Pinned,
|
||||
"update_time": now,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "更新失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
note.Title = payload.Title
|
||||
note.Content = payload.Content
|
||||
note.Pinned = payload.Pinned
|
||||
note.UpdateTime = &now
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "更新成功", note)
|
||||
}
|
||||
|
||||
// Delete 删除笔记(软删除)
|
||||
// DELETE /platform/notebook/delete/:id
|
||||
func (c *PlatformNotebookController) Delete() {
|
||||
claims, err := requireNotebookAuth(&c.Controller)
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 401, 401, "未登录或无权限", nil)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonResponse(&c.Controller, 400, 400, "无效ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证笔记是否存在且属于当前用户
|
||||
var note models.PlatformNotebook
|
||||
err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("user_id", claims.UserID).
|
||||
One(¬e)
|
||||
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
jsonResponse(&c.Controller, 404, 404, "笔记不存在", nil)
|
||||
} else {
|
||||
jsonResponse(&c.Controller, 500, 500, "查询失败", nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformNotebook)).
|
||||
Filter("id", id).
|
||||
Update(map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"delete_time": now,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
jsonResponse(&c.Controller, 500, 500, "删除失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(&c.Controller, 200, 200, "删除成功", nil)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// PlatformNotebook 平台记事本表: yz_platform_notebook
|
||||
type PlatformNotebook struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Title string `orm:"column(title);size(255)" json:"title"`
|
||||
Content string `orm:"column(content);type(longtext);null" json:"content"`
|
||||
UserID *uint64 `orm:"column(user_id);null" json:"user_id"`
|
||||
UserName *string `orm:"column(user_name);size(100);null" json:"user_name"`
|
||||
IsDeleted int8 `orm:"column(is_deleted);default(0)" json:"is_deleted"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *PlatformNotebook) TableName() string {
|
||||
return "yz_platform_notebook"
|
||||
}
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// PlatformNotebook 平台记事本表: yz_platform_notebook
|
||||
type PlatformNotebook struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Title string `orm:"column(title);size(255)" json:"title"`
|
||||
Content string `orm:"column(content);type(longtext);null" json:"content"`
|
||||
Pinned int8 `orm:"column(pinned);default(0)" json:"pinned"`
|
||||
UserID *uint64 `orm:"column(user_id);null" json:"user_id"`
|
||||
UserName *string `orm:"column(user_name);size(100);null" json:"user_name"`
|
||||
IsDeleted int8 `orm:"column(is_deleted);default(0)" json:"is_deleted"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *PlatformNotebook) TableName() string {
|
||||
return "yz_platform_notebook"
|
||||
}
|
||||
|
||||
+24
-23
@@ -1,23 +1,24 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type SystemTenant struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantCode string `orm:"column(tenant_code);size(32)" json:"tenant_code"`
|
||||
TenantName string `orm:"column(tenant_name);size(128)" json:"tenant_name"`
|
||||
ContactPerson *string `orm:"column(contact_person);size(64);null" json:"contact_person"`
|
||||
ContactPhone *string `orm:"column(contact_phone);size(20);null" json:"contact_phone"`
|
||||
ContactEmail *string `orm:"column(contact_email);size(128);null" json:"contact_email"`
|
||||
Address *string `orm:"column(address);size(255);null" json:"address"`
|
||||
Worktime *string `orm:"column(worktime);size(255);null" json:"worktime"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
Remark *string `orm:"column(remark);size(512);null" json:"remark"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *SystemTenant) TableName() string {
|
||||
return "yz_system_tenant"
|
||||
}
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type SystemTenant struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantCode string `orm:"column(tenant_code);size(32)" json:"tenant_code"`
|
||||
TenantName string `orm:"column(tenant_name);size(128)" json:"tenant_name"`
|
||||
TenantShortName *string `orm:"column(tenant_short_name);size(128);null" json:"tenant_short_name"`
|
||||
ContactPerson *string `orm:"column(contact_person);size(64);null" json:"contact_person"`
|
||||
ContactPhone *string `orm:"column(contact_phone);size(20);null" json:"contact_phone"`
|
||||
ContactEmail *string `orm:"column(contact_email);size(128);null" json:"contact_email"`
|
||||
Address *string `orm:"column(address);size(255);null" json:"address"`
|
||||
Worktime *string `orm:"column(worktime);size(255);null" json:"worktime"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
Remark *string `orm:"column(remark);size(512);null" json:"remark"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *SystemTenant) TableName() string {
|
||||
return "yz_system_tenant"
|
||||
}
|
||||
|
||||
+232
-232
@@ -1,232 +1,232 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
)
|
||||
|
||||
type loginCodeItem struct {
|
||||
Code string
|
||||
Channel string
|
||||
ExpiredAt time.Time
|
||||
}
|
||||
|
||||
var loginCodeStore sync.Map
|
||||
|
||||
func codeKey(account, channel string) string {
|
||||
return strings.ToLower(strings.TrimSpace(account)) + "|" + strings.TrimSpace(channel)
|
||||
}
|
||||
|
||||
func SendPlatformLoginCode(account, channel string) error {
|
||||
account = strings.TrimSpace(account)
|
||||
channel = strings.TrimSpace(channel)
|
||||
if account == "" {
|
||||
return errors.New("账号不能为空")
|
||||
}
|
||||
if channel != "sms" && channel != "email" {
|
||||
return errors.New("仅支持短信或邮箱验证码")
|
||||
}
|
||||
|
||||
var u models.AdminUser
|
||||
if err := models.Orm.QueryTable(new(models.AdminUser)).Filter("account", account).One(&u); err != nil {
|
||||
return errors.New("用户不存在")
|
||||
}
|
||||
if u.Status == 0 {
|
||||
return errors.New("账号已禁用")
|
||||
}
|
||||
if channel == "sms" && (u.Phone == nil || strings.TrimSpace(*u.Phone) == "") {
|
||||
return errors.New("该账号未绑定手机号")
|
||||
}
|
||||
if channel == "email" && (u.Email == nil || strings.TrimSpace(*u.Email) == "") {
|
||||
return errors.New("该账号未绑定邮箱")
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
loginCodeStore.Store(codeKey(account, channel), loginCodeItem{
|
||||
Code: code,
|
||||
Channel: channel,
|
||||
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyPlatformLoginCode(account, channel, code string) error {
|
||||
account = strings.TrimSpace(account)
|
||||
channel = strings.TrimSpace(channel)
|
||||
code = strings.TrimSpace(code)
|
||||
if account == "" || code == "" {
|
||||
return errors.New("验证码不能为空")
|
||||
}
|
||||
val, ok := loginCodeStore.Load(codeKey(account, channel))
|
||||
if !ok {
|
||||
return errors.New("验证码不存在或已失效")
|
||||
}
|
||||
item, ok := val.(loginCodeItem)
|
||||
if !ok {
|
||||
return errors.New("验证码状态异常")
|
||||
}
|
||||
if time.Now().After(item.ExpiredAt) {
|
||||
loginCodeStore.Delete(codeKey(account, channel))
|
||||
return errors.New("验证码已过期")
|
||||
}
|
||||
if item.Code != code {
|
||||
return errors.New("验证码错误")
|
||||
}
|
||||
loginCodeStore.Delete(codeKey(account, channel))
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendBackendLoginCode(tenantName, account, channel string) error {
|
||||
tenantName = strings.TrimSpace(tenantName)
|
||||
account = strings.TrimSpace(account)
|
||||
channel = strings.TrimSpace(channel)
|
||||
if tenantName == "" || account == "" {
|
||||
return errors.New("租户名称和账号不能为空")
|
||||
}
|
||||
if channel != "sms" && channel != "email" {
|
||||
return errors.New("仅支持短信或邮箱验证码")
|
||||
}
|
||||
|
||||
var tenant models.SystemTenant
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenant)).Filter("tenant_name", tenantName).One(&tenant); err != nil {
|
||||
return errors.New("租户不存在")
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
|
||||
switch channel {
|
||||
case "sms":
|
||||
phone := account
|
||||
var user models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tenant.ID).
|
||||
Filter("phone", phone).
|
||||
One(&user); err != nil {
|
||||
return errors.New("该手机号非当前企业绑定号码,请重试")
|
||||
}
|
||||
if user.Status == 0 {
|
||||
return errors.New("账号已禁用")
|
||||
}
|
||||
if user.Phone == nil || strings.TrimSpace(*user.Phone) == "" {
|
||||
return errors.New("该手机号非当前企业绑定号码,请重试")
|
||||
}
|
||||
|
||||
content := "短信验证码:" + code
|
||||
if err := enqueueSMSTaskForLogin(tenant.ID, phone, content, code); err != nil {
|
||||
return errors.New("短信发送失败,请重试")
|
||||
}
|
||||
case "email":
|
||||
email := account
|
||||
var user models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tenant.ID).
|
||||
Filter("email", email).
|
||||
One(&user); err != nil {
|
||||
return errors.New("该账号未绑定邮箱")
|
||||
}
|
||||
if user.Status == 0 {
|
||||
return errors.New("账号已禁用")
|
||||
}
|
||||
if user.Email == nil || strings.TrimSpace(*user.Email) == "" {
|
||||
return errors.New("该账号未绑定邮箱")
|
||||
}
|
||||
}
|
||||
|
||||
loginCodeStore.Store(codeKey(tenantName+"#"+account, channel), loginCodeItem{
|
||||
Code: code,
|
||||
Channel: channel,
|
||||
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyBackendLoginCode(tenantName, account, channel, code string) error {
|
||||
return VerifyPlatformLoginCode(tenantName+"#"+account, channel, code)
|
||||
}
|
||||
|
||||
func getDefaultSystemSMSConfig() (backendURL string, apiKey string, err error) {
|
||||
backendURL = models.GetPlatformSettingValue("sms_custom_url", "")
|
||||
apiKey = models.GetPlatformSettingValue("sms_custom_key", "")
|
||||
if backendURL == "" || apiKey == "" {
|
||||
return "", "", fmt.Errorf("短信网关未配置")
|
||||
}
|
||||
return backendURL, apiKey, nil
|
||||
}
|
||||
|
||||
// enqueueSMSTaskForLogin 入队短信任务到网关,并写入 yz_system_sms_tasks
|
||||
func enqueueSMSTaskForLogin(tid uint64, phone, content, code string) error {
|
||||
backendURL, apiKey, err := getDefaultSystemSMSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backendURL == "" || apiKey == "" {
|
||||
return errors.New("短信网关未配置")
|
||||
}
|
||||
|
||||
enqueueURL := strings.TrimRight(backendURL, "/") + "/api/v1/business/outbound-tasks"
|
||||
payload := map[string]interface{}{
|
||||
"phone": phone,
|
||||
"content": content,
|
||||
}
|
||||
bs, _ := json.Marshal(payload)
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
req, err := http.NewRequest("POST", enqueueURL, bytes.NewReader(bs))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("X-Api-Key", apiKey)
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
bodyStr := strings.TrimSpace(string(bodyBytes))
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("gateway http status: %d, body: %s", resp.StatusCode, bodyStr)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
tidCopy := tid
|
||||
contentPtr := content
|
||||
var reportPtr *string
|
||||
if bodyStr != "" {
|
||||
reportPtr = &bodyStr
|
||||
}
|
||||
|
||||
task := &models.SystemSMSTask{
|
||||
Tid: &tidCopy,
|
||||
ApiKey: apiKey,
|
||||
Phone: phone,
|
||||
Content: &contentPtr,
|
||||
Status: 3,
|
||||
Code: code,
|
||||
ReportRaw: reportPtr,
|
||||
CreateTime: &now,
|
||||
UpdateTime: &now,
|
||||
}
|
||||
|
||||
_, insertErr := models.Orm.Insert(task)
|
||||
if insertErr != nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
)
|
||||
|
||||
type loginCodeItem struct {
|
||||
Code string
|
||||
Channel string
|
||||
ExpiredAt time.Time
|
||||
}
|
||||
|
||||
var loginCodeStore sync.Map
|
||||
|
||||
func codeKey(account, channel string) string {
|
||||
return strings.ToLower(strings.TrimSpace(account)) + "|" + strings.TrimSpace(channel)
|
||||
}
|
||||
|
||||
func SendPlatformLoginCode(account, channel string) error {
|
||||
account = strings.TrimSpace(account)
|
||||
channel = strings.TrimSpace(channel)
|
||||
if account == "" {
|
||||
return errors.New("账号不能为空")
|
||||
}
|
||||
if channel != "sms" && channel != "email" {
|
||||
return errors.New("仅支持短信或邮箱验证码")
|
||||
}
|
||||
|
||||
var u models.AdminUser
|
||||
if err := models.Orm.QueryTable(new(models.AdminUser)).Filter("account", account).One(&u); err != nil {
|
||||
return errors.New("用户不存在")
|
||||
}
|
||||
if u.Status == 0 {
|
||||
return errors.New("账号已禁用")
|
||||
}
|
||||
if channel == "sms" && (u.Phone == nil || strings.TrimSpace(*u.Phone) == "") {
|
||||
return errors.New("该账号未绑定手机号")
|
||||
}
|
||||
if channel == "email" && (u.Email == nil || strings.TrimSpace(*u.Email) == "") {
|
||||
return errors.New("该账号未绑定邮箱")
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
loginCodeStore.Store(codeKey(account, channel), loginCodeItem{
|
||||
Code: code,
|
||||
Channel: channel,
|
||||
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyPlatformLoginCode(account, channel, code string) error {
|
||||
account = strings.TrimSpace(account)
|
||||
channel = strings.TrimSpace(channel)
|
||||
code = strings.TrimSpace(code)
|
||||
if account == "" || code == "" {
|
||||
return errors.New("验证码不能为空")
|
||||
}
|
||||
val, ok := loginCodeStore.Load(codeKey(account, channel))
|
||||
if !ok {
|
||||
return errors.New("验证码不存在或已失效")
|
||||
}
|
||||
item, ok := val.(loginCodeItem)
|
||||
if !ok {
|
||||
return errors.New("验证码状态异常")
|
||||
}
|
||||
if time.Now().After(item.ExpiredAt) {
|
||||
loginCodeStore.Delete(codeKey(account, channel))
|
||||
return errors.New("验证码已过期")
|
||||
}
|
||||
if item.Code != code {
|
||||
return errors.New("验证码错误")
|
||||
}
|
||||
loginCodeStore.Delete(codeKey(account, channel))
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendBackendLoginCode(tenantName, account, channel string) error {
|
||||
tenantName = strings.TrimSpace(tenantName)
|
||||
account = strings.TrimSpace(account)
|
||||
channel = strings.TrimSpace(channel)
|
||||
if tenantName == "" || account == "" {
|
||||
return errors.New("租户名称和账号不能为空")
|
||||
}
|
||||
if channel != "sms" && channel != "email" {
|
||||
return errors.New("仅支持短信或邮箱验证码")
|
||||
}
|
||||
|
||||
tenant, err := findTenantByLoginName(tenantName)
|
||||
if err != nil {
|
||||
return errors.New("租户不存在")
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
|
||||
switch channel {
|
||||
case "sms":
|
||||
phone := account
|
||||
var user models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tenant.ID).
|
||||
Filter("phone", phone).
|
||||
One(&user); err != nil {
|
||||
return errors.New("该手机号非当前企业绑定号码,请重试")
|
||||
}
|
||||
if user.Status == 0 {
|
||||
return errors.New("账号已禁用")
|
||||
}
|
||||
if user.Phone == nil || strings.TrimSpace(*user.Phone) == "" {
|
||||
return errors.New("该手机号非当前企业绑定号码,请重试")
|
||||
}
|
||||
|
||||
content := "短信验证码:" + code
|
||||
if err := enqueueSMSTaskForLogin(tenant.ID, phone, content, code); err != nil {
|
||||
return errors.New("短信发送失败,请重试")
|
||||
}
|
||||
case "email":
|
||||
email := account
|
||||
var user models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tenant.ID).
|
||||
Filter("email", email).
|
||||
One(&user); err != nil {
|
||||
return errors.New("该账号未绑定邮箱")
|
||||
}
|
||||
if user.Status == 0 {
|
||||
return errors.New("账号已禁用")
|
||||
}
|
||||
if user.Email == nil || strings.TrimSpace(*user.Email) == "" {
|
||||
return errors.New("该账号未绑定邮箱")
|
||||
}
|
||||
}
|
||||
|
||||
loginCodeStore.Store(codeKey(tenantName+"#"+account, channel), loginCodeItem{
|
||||
Code: code,
|
||||
Channel: channel,
|
||||
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyBackendLoginCode(tenantName, account, channel, code string) error {
|
||||
return VerifyPlatformLoginCode(tenantName+"#"+account, channel, code)
|
||||
}
|
||||
|
||||
func getDefaultSystemSMSConfig() (backendURL string, apiKey string, err error) {
|
||||
backendURL = models.GetPlatformSettingValue("sms_custom_url", "")
|
||||
apiKey = models.GetPlatformSettingValue("sms_custom_key", "")
|
||||
if backendURL == "" || apiKey == "" {
|
||||
return "", "", fmt.Errorf("短信网关未配置")
|
||||
}
|
||||
return backendURL, apiKey, nil
|
||||
}
|
||||
|
||||
// enqueueSMSTaskForLogin 入队短信任务到网关,并写入 yz_system_sms_tasks
|
||||
func enqueueSMSTaskForLogin(tid uint64, phone, content, code string) error {
|
||||
backendURL, apiKey, err := getDefaultSystemSMSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backendURL == "" || apiKey == "" {
|
||||
return errors.New("短信网关未配置")
|
||||
}
|
||||
|
||||
enqueueURL := strings.TrimRight(backendURL, "/") + "/api/v1/business/outbound-tasks"
|
||||
payload := map[string]interface{}{
|
||||
"phone": phone,
|
||||
"content": content,
|
||||
}
|
||||
bs, _ := json.Marshal(payload)
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
req, err := http.NewRequest("POST", enqueueURL, bytes.NewReader(bs))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("X-Api-Key", apiKey)
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
bodyStr := strings.TrimSpace(string(bodyBytes))
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("gateway http status: %d, body: %s", resp.StatusCode, bodyStr)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
tidCopy := tid
|
||||
contentPtr := content
|
||||
var reportPtr *string
|
||||
if bodyStr != "" {
|
||||
reportPtr = &bodyStr
|
||||
}
|
||||
|
||||
task := &models.SystemSMSTask{
|
||||
Tid: &tidCopy,
|
||||
ApiKey: apiKey,
|
||||
Phone: phone,
|
||||
Content: &contentPtr,
|
||||
Status: 3,
|
||||
Code: code,
|
||||
ReportRaw: reportPtr,
|
||||
CreateTime: &now,
|
||||
UpdateTime: &now,
|
||||
}
|
||||
|
||||
_, insertErr := models.Orm.Insert(task)
|
||||
if insertErr != nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+155
-158
@@ -1,158 +1,155 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
"server/pkg/passwordutil"
|
||||
)
|
||||
|
||||
type PlatformLoginUser struct {
|
||||
ID uint64
|
||||
Account string
|
||||
Name string
|
||||
Tid uint64
|
||||
Rid uint64
|
||||
Avatar string
|
||||
RoleName string
|
||||
}
|
||||
|
||||
func adminRoleNameByID(roleID uint64) string {
|
||||
if roleID == 0 {
|
||||
return ""
|
||||
}
|
||||
var role models.AdminRole
|
||||
err := models.Orm.QueryTable(new(models.AdminRole)).Filter("id", roleID).One(&role)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return role.Name
|
||||
}
|
||||
|
||||
func toPlatformLoginUser(user *models.AdminUser) *PlatformLoginUser {
|
||||
name := ""
|
||||
if user.Name != nil {
|
||||
name = *user.Name
|
||||
}
|
||||
avatar := ""
|
||||
if user.Avatar != nil {
|
||||
avatar = *user.Avatar
|
||||
}
|
||||
return &PlatformLoginUser{
|
||||
ID: user.ID,
|
||||
Account: user.Account,
|
||||
Name: name,
|
||||
Tid: 0,
|
||||
Rid: user.RoleID,
|
||||
Avatar: avatar,
|
||||
RoleName: adminRoleNameByID(user.RoleID),
|
||||
}
|
||||
}
|
||||
|
||||
// PlatformAdminLogin 平台端登录:仅校验 yz_system_admin_user,不需要租户。
|
||||
func PlatformAdminLogin(account, password string) (string, *PlatformLoginUser, error) {
|
||||
account = strings.TrimSpace(account)
|
||||
password = strings.TrimSpace(password)
|
||||
if account == "" || password == "" {
|
||||
return "", nil, errors.New("用户名或密码不能为空")
|
||||
}
|
||||
|
||||
var user models.AdminUser
|
||||
err := models.Orm.QueryTable(new(models.AdminUser)).
|
||||
Filter("account", account).
|
||||
One(&user)
|
||||
if err != nil {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
if user.Status == 0 {
|
||||
return "", nil, errors.New("账号已禁用")
|
||||
}
|
||||
if !passwordutil.Verify(user.Password, password) {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
const tenantID = 0
|
||||
const userType = "platform"
|
||||
token, err := jwtutil.GenerateToken(int(user.ID), user.Account, tenantID, userType)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
loginUser := toPlatformLoginUser(&user)
|
||||
return token, loginUser, nil
|
||||
}
|
||||
|
||||
// BackendLogin backend 登录:先校验租户,再校验租户下用户账号和密码。
|
||||
func BackendLogin(tenantName, account, password string) (string, *PlatformLoginUser, error) {
|
||||
tenantName = strings.TrimSpace(tenantName)
|
||||
account = strings.TrimSpace(account)
|
||||
password = strings.TrimSpace(password)
|
||||
if tenantName == "" || account == "" || password == "" {
|
||||
return "", nil, errors.New("租户名称、用户名或密码不能为空")
|
||||
}
|
||||
|
||||
var tenant models.SystemTenant
|
||||
err := models.Orm.QueryTable(new(models.SystemTenant)).
|
||||
Filter("tenant_name", tenantName).
|
||||
One(&tenant)
|
||||
if err != nil {
|
||||
return "", nil, errors.New("租户不存在")
|
||||
}
|
||||
if tenant.Status != 1 {
|
||||
return "", nil, errors.New("租户已停用")
|
||||
}
|
||||
|
||||
var tenantUser models.SystemTenantUser
|
||||
err = models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tenant.ID).
|
||||
Filter("account", account).
|
||||
One(&tenantUser)
|
||||
if err != nil {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
if tenantUser.Status == 0 {
|
||||
return "", nil, errors.New("账号已禁用")
|
||||
}
|
||||
if tenantUser.Password == nil || !passwordutil.Verify(*tenantUser.Password, password) {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
tenantID := int(tenant.ID)
|
||||
const userType = "backend"
|
||||
token, err := jwtutil.GenerateToken(int(tenantUser.Uid), account, tenantID, userType)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
loginUser := &PlatformLoginUser{
|
||||
ID: tenantUser.Uid,
|
||||
Account: account,
|
||||
Name: "",
|
||||
Tid: tenant.ID,
|
||||
Rid: 0,
|
||||
Avatar: "",
|
||||
RoleName: "",
|
||||
}
|
||||
if tenantUser.Account != nil && strings.TrimSpace(*tenantUser.Account) != "" {
|
||||
loginUser.Account = strings.TrimSpace(*tenantUser.Account)
|
||||
}
|
||||
if tenantUser.Name != nil {
|
||||
loginUser.Name = strings.TrimSpace(*tenantUser.Name)
|
||||
}
|
||||
|
||||
return token, loginUser, nil
|
||||
}
|
||||
|
||||
// PlatformGetCurrentUser 根据平台管理员用户 ID 返回登录用户信息(含角色名称)。
|
||||
func PlatformGetCurrentUser(uid uint64) (*PlatformLoginUser, error) {
|
||||
u, err := GetAdminUserByID(uid)
|
||||
if err != nil {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
if u.Status == 0 {
|
||||
return nil, errors.New("账号已禁用")
|
||||
}
|
||||
return toPlatformLoginUser(u), nil
|
||||
}
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
"server/pkg/passwordutil"
|
||||
)
|
||||
|
||||
type PlatformLoginUser struct {
|
||||
ID uint64
|
||||
Account string
|
||||
Name string
|
||||
Tid uint64
|
||||
Rid uint64
|
||||
Avatar string
|
||||
RoleName string
|
||||
}
|
||||
|
||||
func adminRoleNameByID(roleID uint64) string {
|
||||
if roleID == 0 {
|
||||
return ""
|
||||
}
|
||||
var role models.AdminRole
|
||||
err := models.Orm.QueryTable(new(models.AdminRole)).Filter("id", roleID).One(&role)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return role.Name
|
||||
}
|
||||
|
||||
func toPlatformLoginUser(user *models.AdminUser) *PlatformLoginUser {
|
||||
name := ""
|
||||
if user.Name != nil {
|
||||
name = *user.Name
|
||||
}
|
||||
avatar := ""
|
||||
if user.Avatar != nil {
|
||||
avatar = *user.Avatar
|
||||
}
|
||||
return &PlatformLoginUser{
|
||||
ID: user.ID,
|
||||
Account: user.Account,
|
||||
Name: name,
|
||||
Tid: 0,
|
||||
Rid: user.RoleID,
|
||||
Avatar: avatar,
|
||||
RoleName: adminRoleNameByID(user.RoleID),
|
||||
}
|
||||
}
|
||||
|
||||
// PlatformAdminLogin 平台端登录:仅校验 yz_system_admin_user,不需要租户。
|
||||
func PlatformAdminLogin(account, password string) (string, *PlatformLoginUser, error) {
|
||||
account = strings.TrimSpace(account)
|
||||
password = strings.TrimSpace(password)
|
||||
if account == "" || password == "" {
|
||||
return "", nil, errors.New("用户名或密码不能为空")
|
||||
}
|
||||
|
||||
var user models.AdminUser
|
||||
err := models.Orm.QueryTable(new(models.AdminUser)).
|
||||
Filter("account", account).
|
||||
One(&user)
|
||||
if err != nil {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
if user.Status == 0 {
|
||||
return "", nil, errors.New("账号已禁用")
|
||||
}
|
||||
if !passwordutil.Verify(user.Password, password) {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
const tenantID = 0
|
||||
const userType = "platform"
|
||||
token, err := jwtutil.GenerateToken(int(user.ID), user.Account, tenantID, userType)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
loginUser := toPlatformLoginUser(&user)
|
||||
return token, loginUser, nil
|
||||
}
|
||||
|
||||
// BackendLogin backend 登录:先校验租户,再校验租户下用户账号和密码。
|
||||
func BackendLogin(tenantName, account, password string) (string, *PlatformLoginUser, error) {
|
||||
tenantName = strings.TrimSpace(tenantName)
|
||||
account = strings.TrimSpace(account)
|
||||
password = strings.TrimSpace(password)
|
||||
if tenantName == "" || account == "" || password == "" {
|
||||
return "", nil, errors.New("租户名称、用户名或密码不能为空")
|
||||
}
|
||||
|
||||
tenant, err := findTenantByLoginName(tenantName)
|
||||
if err != nil {
|
||||
return "", nil, errors.New("租户不存在")
|
||||
}
|
||||
if tenant.Status != 1 {
|
||||
return "", nil, errors.New("租户已停用")
|
||||
}
|
||||
|
||||
var tenantUser models.SystemTenantUser
|
||||
err = models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tenant.ID).
|
||||
Filter("account", account).
|
||||
One(&tenantUser)
|
||||
if err != nil {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
if tenantUser.Status == 0 {
|
||||
return "", nil, errors.New("账号已禁用")
|
||||
}
|
||||
if tenantUser.Password == nil || !passwordutil.Verify(*tenantUser.Password, password) {
|
||||
return "", nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
tenantID := int(tenant.ID)
|
||||
const userType = "backend"
|
||||
token, err := jwtutil.GenerateToken(int(tenantUser.Uid), account, tenantID, userType)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
loginUser := &PlatformLoginUser{
|
||||
ID: tenantUser.Uid,
|
||||
Account: account,
|
||||
Name: "",
|
||||
Tid: tenant.ID,
|
||||
Rid: 0,
|
||||
Avatar: "",
|
||||
RoleName: "",
|
||||
}
|
||||
if tenantUser.Account != nil && strings.TrimSpace(*tenantUser.Account) != "" {
|
||||
loginUser.Account = strings.TrimSpace(*tenantUser.Account)
|
||||
}
|
||||
if tenantUser.Name != nil {
|
||||
loginUser.Name = strings.TrimSpace(*tenantUser.Name)
|
||||
}
|
||||
|
||||
return token, loginUser, nil
|
||||
}
|
||||
|
||||
// PlatformGetCurrentUser 根据平台管理员用户 ID 返回登录用户信息(含角色名称)。
|
||||
func PlatformGetCurrentUser(uid uint64) (*PlatformLoginUser, error) {
|
||||
u, err := GetAdminUserByID(uid)
|
||||
if err != nil {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
if u.Status == 0 {
|
||||
return nil, errors.New("账号已禁用")
|
||||
}
|
||||
return toPlatformLoginUser(u), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
|
||||
"server/models"
|
||||
)
|
||||
|
||||
/* findTenantByLoginName 根据租户简称、短名或编码查找租户。
|
||||
*
|
||||
* 当前表结构中 tenant_name 的业务含义就是“租户简称”,同时兼容
|
||||
* tenant_short_name 和 tenant_code 两个历史/备用登录标识。
|
||||
*/
|
||||
func findTenantByLoginName(loginName string) (*models.SystemTenant, error) {
|
||||
loginName = strings.TrimSpace(loginName)
|
||||
if loginName == "" {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
|
||||
// tenant_name 的业务含义是租户简称。使用 TRIM 兼容历史数据中字段值
|
||||
// 前后存在空格的情况;参数通过 SetArgs 绑定,避免 SQL 注入。
|
||||
tenant := &models.SystemTenant{}
|
||||
query := `
|
||||
SELECT id, tenant_code, tenant_name, tenant_short_name,
|
||||
contact_person, contact_phone, contact_email, address,
|
||||
worktime, status, remark, create_time, update_time, delete_time
|
||||
FROM yz_system_tenant
|
||||
WHERE (TRIM(tenant_name) = TRIM(?) OR
|
||||
TRIM(tenant_short_name) = TRIM(?) OR
|
||||
TRIM(tenant_code) = TRIM(?))
|
||||
AND status <> 0
|
||||
ORDER BY id ASC
|
||||
LIMIT 1`
|
||||
err := models.Orm.Raw(query).
|
||||
SetArgs(loginName, loginName, loginName).
|
||||
QueryRow(tenant)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenant, nil
|
||||
}
|
||||
Reference in New Issue
Block a user