go-platform/controllers/platform_domain.go

616 lines
17 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controllers
import (
"encoding/json"
"fmt"
"io"
"regexp"
"strconv"
"strings"
"time"
"server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// PlatformDomainPoolController 主域名池管理
type PlatformDomainPoolController struct {
beego.Controller
}
// PlatformTenantDomainController 租户域名管理
type PlatformTenantDomainController struct {
beego.Controller
}
func requirePlatform(c *beego.Controller) (*jwtutil.Claims, error) {
auth := c.Ctx.Request.Header.Get("Authorization")
if auth == "" {
return nil, fmt.Errorf("未登录")
}
parts := strings.SplitN(auth, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
return nil, fmt.Errorf("认证信息格式错误")
}
claims, err := jwtutil.ParseToken(parts[1])
if err != nil {
return nil, fmt.Errorf("无效的token")
}
if claims.UserType != "platform" {
return nil, fmt.Errorf("无权访问")
}
return claims, nil
}
func jsonErr(c *beego.Controller, httpStatus, bizCode int, msg string) {
c.Ctx.Output.SetStatus(httpStatus)
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
_ = c.ServeJSON()
}
// ===== 主域名池 =====
// Index GET /platform/domain/pool/index?page=&pageSize=&main_domain=&status=
func (c *PlatformDomainPoolController) Index() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 10)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 10
}
if pageSize > 200 {
pageSize = 200
}
mainDomain := strings.TrimSpace(c.GetString("main_domain"))
statusStr := strings.TrimSpace(c.GetString("status"))
qs := models.Orm.QueryTable(new(models.SystemDomainPool)).Filter("delete_time__isnull", true)
if mainDomain != "" {
qs = qs.Filter("main_domain__icontains", mainDomain)
}
if statusStr != "" {
if st, err := strconv.Atoi(statusStr); err == nil {
qs = qs.Filter("status", st)
}
}
total, err := qs.Count()
if err != nil {
jsonErr(&c.Controller, 500, 500, "获取主域名池失败: "+err.Error())
return
}
var rows []models.SystemDomainPool
_, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows)
if err != nil {
jsonErr(&c.Controller, 500, 500, "获取主域名池失败: "+err.Error())
return
}
list := make([]map[string]interface{}, 0, len(rows))
for i := range rows {
item := map[string]interface{}{
"id": rows[i].ID,
"main_domain": rows[i].MainDomain,
"status": rows[i].Status,
"create_time": rows[i].CreateTime.Format("2006-01-02 15:04:05"),
"update_time": "",
}
if rows[i].UpdateTime != nil {
item["update_time"] = rows[i].UpdateTime.Format("2006-01-02 15:04:05")
}
list = append(list, item)
}
c.Data["json"] = map[string]interface{}{
"code": 200,
"msg": "success",
"data": map[string]interface{}{
"list": list,
"total": total,
},
}
_ = c.ServeJSON()
}
// GetEnabledDomains GET /platform/domain/pool/getEnabledDomains
func (c *PlatformDomainPoolController) GetEnabledDomains() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
var rows []models.SystemDomainPool
_, err := models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("status", 1).
Filter("delete_time__isnull", true).
OrderBy("-id").
All(&rows)
if err != nil {
jsonErr(&c.Controller, 500, 500, "获取主域名失败: "+err.Error())
return
}
out := make([]map[string]interface{}, 0, len(rows))
for i := range rows {
out = append(out, map[string]interface{}{
"id": rows[i].ID,
"main_domain": rows[i].MainDomain,
"status": rows[i].Status,
})
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": out}
_ = c.ServeJSON()
}
type domainPoolPayload struct {
ID uint64 `json:"id"`
MainDomain string `json:"main_domain"`
Status int8 `json:"status"`
}
// Create POST /platform/domain/pool/create
func (c *PlatformDomainPoolController) Create() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var p domainPoolPayload
if err := json.Unmarshal(raw, &p); err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
md := strings.TrimSpace(p.MainDomain)
if md == "" {
jsonErr(&c.Controller, 400, 400, "主域名不能为空")
return
}
if p.Status != 0 && p.Status != 1 {
p.Status = 1
}
// 简单去重
cnt, _ := models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("main_domain", md).
Filter("delete_time__isnull", true).
Count()
if cnt > 0 {
jsonErr(&c.Controller, 400, 400, "主域名已存在")
return
}
row := &models.SystemDomainPool{MainDomain: md, Status: p.Status}
if _, err := models.Orm.Insert(row); err != nil {
jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "创建成功"}
_ = c.ServeJSON()
}
// Update POST /platform/domain/pool/update
func (c *PlatformDomainPoolController) Update() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var p domainPoolPayload
if err := json.Unmarshal(raw, &p); err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
if p.ID == 0 {
jsonErr(&c.Controller, 400, 400, "id 不能为空")
return
}
md := strings.TrimSpace(p.MainDomain)
if md == "" {
jsonErr(&c.Controller, 400, 400, "主域名不能为空")
return
}
if p.Status != 0 && p.Status != 1 {
p.Status = 1
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("id", p.ID).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{"main_domain": md, "status": p.Status, "update_time": now})
if err != nil {
jsonErr(&c.Controller, 500, 500, "更新失败: "+err.Error())
return
}
if n == 0 {
jsonErr(&c.Controller, 404, 404, "记录不存在")
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "更新成功"}
_ = c.ServeJSON()
}
// Delete DELETE /platform/domain/pool/delete/:id
func (c *PlatformDomainPoolController) Delete() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 {
jsonErr(&c.Controller, 400, 400, "无效ID")
return
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("id", id).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now, "update_time": now})
if err != nil {
jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error())
return
}
if n == 0 {
jsonErr(&c.Controller, 404, 404, "记录不存在")
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功"}
_ = c.ServeJSON()
}
// ToggleStatus POST /platform/domain/pool/toggleStatus body:{id}
func (c *PlatformDomainPoolController) ToggleStatus() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var p struct {
ID uint64 `json:"id"`
}
if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var row models.SystemDomainPool
if err := models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("id", p.ID).
Filter("delete_time__isnull", true).
One(&row); err != nil {
jsonErr(&c.Controller, 404, 404, "记录不存在")
return
}
newStatus := int8(1)
if row.Status == 1 {
newStatus = 0
}
now := time.Now()
_, err = models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("id", p.ID).
Update(map[string]interface{}{"status": newStatus, "update_time": now})
if err != nil {
jsonErr(&c.Controller, 500, 500, "切换失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"}
_ = c.ServeJSON()
}
// ===== 租户域名 =====
// Index GET /platform/domain/tenant/index?page=&pageSize=&tid=&status=&sub_domain=
func (c *PlatformTenantDomainController) Index() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 10)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 10
}
if pageSize > 200 {
pageSize = 200
}
tid, _ := c.GetUint64("tid")
statusStr := strings.TrimSpace(c.GetString("status"))
subDomain := strings.TrimSpace(c.GetString("sub_domain"))
qs := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("delete_time__isnull", true)
if tid > 0 {
qs = qs.Filter("tid", tid)
}
if statusStr != "" {
if st, err := strconv.Atoi(statusStr); err == nil {
qs = qs.Filter("status", st)
}
}
if subDomain != "" {
qs = qs.Filter("sub_domain__icontains", subDomain)
}
total, err := qs.Count()
if err != nil {
jsonErr(&c.Controller, 500, 500, "获取租户域名失败: "+err.Error())
return
}
var rows []models.SystemTenantDomain
_, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows)
if err != nil {
jsonErr(&c.Controller, 500, 500, "获取租户域名失败: "+err.Error())
return
}
list := make([]models.SystemTenantDomain, 0, len(rows))
list = append(list, rows...)
c.Data["json"] = map[string]interface{}{
"code": 200,
"msg": "success",
"data": map[string]interface{}{"list": list, "total": total},
}
_ = c.ServeJSON()
}
// MyDomains GET /platform/domain/tenant/myDomains?tid=1
func (c *PlatformTenantDomainController) MyDomains() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
tid, _ := c.GetUint64("tid")
if tid == 0 {
jsonErr(&c.Controller, 400, 400, "租户ID不能为空")
return
}
var rows []models.SystemTenantDomain
_, err := models.Orm.QueryTable(new(models.SystemTenantDomain)).
Filter("tid", tid).
Filter("delete_time__isnull", true).
OrderBy("-id").
All(&rows)
if err != nil {
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": rows}
_ = c.ServeJSON()
}
var subDomainRe = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$`)
// Apply POST /platform/domain/tenant/apply body:{tid,sub_domain,main_domain}
func (c *PlatformTenantDomainController) Apply() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var p struct {
Tid uint64 `json:"tid"`
SubDomain string `json:"sub_domain"`
MainDomain string `json:"main_domain"`
}
if err := json.Unmarshal(raw, &p); err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
if p.Tid == 0 {
jsonErr(&c.Controller, 400, 400, "租户ID不能为空")
return
}
sub := strings.TrimSpace(p.SubDomain)
main := strings.TrimSpace(p.MainDomain)
if sub == "" {
jsonErr(&c.Controller, 400, 400, "二级域名前缀不能为空")
return
}
if main == "" {
jsonErr(&c.Controller, 400, 400, "请选择主域名")
return
}
if !subDomainRe.MatchString(sub) {
jsonErr(&c.Controller, 400, 400, "二级域名前缀格式不正确")
return
}
// 该租户是否已有域名
cnt, _ := models.Orm.QueryTable(new(models.SystemTenantDomain)).
Filter("tid", p.Tid).
Filter("delete_time__isnull", true).
Count()
if cnt > 0 {
jsonErr(&c.Controller, 400, 400, "该租户已有域名,请删除后再次申请")
return
}
// 主域名存在且启用
var pool models.SystemDomainPool
if err := models.Orm.QueryTable(new(models.SystemDomainPool)).
Filter("main_domain", main).
Filter("status", 1).
Filter("delete_time__isnull", true).
One(&pool); err != nil {
jsonErr(&c.Controller, 400, 400, "主域名不存在或已禁用")
return
}
// 二级域名是否已被使用(同主域名下)
used, _ := models.Orm.QueryTable(new(models.SystemTenantDomain)).
Filter("sub_domain", sub).
Filter("main_domain", main).
Filter("delete_time__isnull", true).
Count()
if used > 0 {
jsonErr(&c.Controller, 400, 400, "该二级域名已被使用")
return
}
full := sub + "." + main
now := time.Now()
tid := p.Tid
row := &models.SystemTenantDomain{
Tid: &tid,
SubDomain: &sub,
MainDomain: &main,
FullDomain: &full,
Status: 0,
CreateTime: now,
UpdateTime: &now,
}
id, err := models.Orm.Insert(row)
if err != nil {
jsonErr(&c.Controller, 500, 500, "申请失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "申请提交成功,等待审核", "data": map[string]interface{}{"id": uint64(id)}}
_ = c.ServeJSON()
}
// Audit POST /platform/domain/tenant/audit body:{id,action} action=approve/reject
func (c *PlatformTenantDomainController) Audit() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var p struct {
ID uint64 `json:"id"`
Action string `json:"action"`
}
if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var row models.SystemTenantDomain
if err := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).One(&row); err != nil {
jsonErr(&c.Controller, 404, 404, "域名不存在")
return
}
if row.Status != 0 {
jsonErr(&c.Controller, 400, 400, "该域名已审核过了")
return
}
newStatus := 2
msg := "已拒绝"
if strings.ToLower(strings.TrimSpace(p.Action)) == "approve" {
newStatus = 1
msg = "审核通过"
}
now := time.Now()
_, err = models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).Update(map[string]interface{}{
"status": newStatus,
"update_time": now,
})
if err != nil {
jsonErr(&c.Controller, 500, 500, "审核失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": msg}
_ = c.ServeJSON()
}
// ToggleStatus POST /platform/domain/tenant/toggleStatus body:{id}
func (c *PlatformTenantDomainController) ToggleStatus() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var p struct {
ID uint64 `json:"id"`
}
if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
var row models.SystemTenantDomain
if err := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).One(&row); err != nil {
jsonErr(&c.Controller, 404, 404, "域名不存在")
return
}
if row.Status == 0 {
jsonErr(&c.Controller, 400, 400, "审核中不可操作")
return
}
newStatus := 2
if row.Status == 2 {
newStatus = 1
}
now := time.Now()
_, err = models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).Update(map[string]interface{}{
"status": newStatus,
"update_time": now,
})
if err != nil {
jsonErr(&c.Controller, 500, 500, "操作失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"}
_ = c.ServeJSON()
}
// Delete DELETE /platform/domain/tenant/delete/:id
func (c *PlatformTenantDomainController) Delete() {
if _, err := requirePlatform(&c.Controller); err != nil {
jsonErr(&c.Controller, 401, 401, err.Error())
return
}
idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 {
jsonErr(&c.Controller, 400, 400, "参数错误")
return
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.SystemTenantDomain)).
Filter("id", id).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now, "update_time": now})
if err != nil {
jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error())
return
}
if n == 0 {
jsonErr(&c.Controller, 404, 404, "域名不存在")
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功"}
_ = c.ServeJSON()
}
// 用于复杂筛选时可扩展:当前保留 orm.Condition import避免被 gofmt 删除
var _ = orm.NewCondition