mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-06 13:14:11 +00:00
- Update go.mod module path from mhsanaei/3x-ui/v3 to saeederamy/3x-ui/v3 - Update all 73 Go files' import paths accordingly - Fix README.fa_IR.md install command to point to fork's main branch The fork was referencing the original repo's module path in go.mod and all Go source imports, making it dependent on MHSanaei's namespace at build time. https://claude.ai/code/session_01M6d5atbWjuLTj6UwRHoK5m
180 lines
5.6 KiB
Go
180 lines
5.6 KiB
Go
package controller
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/saeederamy/3x-ui/v3/database/model"
|
|
"github.com/saeederamy/3x-ui/v3/logger"
|
|
"github.com/saeederamy/3x-ui/v3/web/entity"
|
|
"github.com/saeederamy/3x-ui/v3/web/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type CustomGeoController struct {
|
|
BaseController
|
|
customGeoService *service.CustomGeoService
|
|
}
|
|
|
|
func NewCustomGeoController(g *gin.RouterGroup, customGeo *service.CustomGeoService) *CustomGeoController {
|
|
a := &CustomGeoController{customGeoService: customGeo}
|
|
a.initRouter(g)
|
|
return a
|
|
}
|
|
|
|
func (a *CustomGeoController) initRouter(g *gin.RouterGroup) {
|
|
g.GET("/list", a.list)
|
|
g.GET("/aliases", a.aliases)
|
|
g.POST("/add", a.add)
|
|
g.POST("/update/:id", a.update)
|
|
g.POST("/delete/:id", a.delete)
|
|
g.POST("/download/:id", a.download)
|
|
g.POST("/update-all", a.updateAll)
|
|
}
|
|
|
|
func mapCustomGeoErr(c *gin.Context, err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
switch {
|
|
case errors.Is(err, service.ErrCustomGeoInvalidType):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrInvalidType"))
|
|
case errors.Is(err, service.ErrCustomGeoAliasRequired):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrAliasRequired"))
|
|
case errors.Is(err, service.ErrCustomGeoAliasPattern):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrAliasPattern"))
|
|
case errors.Is(err, service.ErrCustomGeoAliasReserved):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrAliasReserved"))
|
|
case errors.Is(err, service.ErrCustomGeoURLRequired):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrUrlRequired"))
|
|
case errors.Is(err, service.ErrCustomGeoInvalidURL):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrInvalidUrl"))
|
|
case errors.Is(err, service.ErrCustomGeoURLScheme):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrUrlScheme"))
|
|
case errors.Is(err, service.ErrCustomGeoURLHost):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrUrlHost"))
|
|
case errors.Is(err, service.ErrCustomGeoDuplicateAlias):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrDuplicateAlias"))
|
|
case errors.Is(err, service.ErrCustomGeoNotFound):
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrNotFound"))
|
|
case errors.Is(err, service.ErrCustomGeoDownload):
|
|
logger.Warning("custom geo download:", err)
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrDownload"))
|
|
case errors.Is(err, service.ErrCustomGeoSSRFBlocked):
|
|
logger.Warning("custom geo SSRF blocked:", err)
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrUrlHost"))
|
|
case errors.Is(err, service.ErrCustomGeoPathTraversal):
|
|
logger.Warning("custom geo path traversal blocked:", err)
|
|
return errors.New(I18nWeb(c, "pages.index.customGeoErrDownload"))
|
|
default:
|
|
return err
|
|
}
|
|
}
|
|
|
|
func (a *CustomGeoController) list(c *gin.Context) {
|
|
list, err := a.customGeoService.GetAll()
|
|
if err != nil {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastList"), mapCustomGeoErr(c, err))
|
|
return
|
|
}
|
|
jsonObj(c, list, nil)
|
|
}
|
|
|
|
func (a *CustomGeoController) aliases(c *gin.Context) {
|
|
out, err := a.customGeoService.GetAliasesForUI()
|
|
if err != nil {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoAliasesError"), mapCustomGeoErr(c, err))
|
|
return
|
|
}
|
|
jsonObj(c, out, nil)
|
|
}
|
|
|
|
type customGeoForm struct {
|
|
Type string `json:"type" form:"type"`
|
|
Alias string `json:"alias" form:"alias"`
|
|
Url string `json:"url" form:"url"`
|
|
}
|
|
|
|
func (a *CustomGeoController) add(c *gin.Context) {
|
|
var form customGeoForm
|
|
if err := c.ShouldBind(&form); err != nil {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastAdd"), err)
|
|
return
|
|
}
|
|
r := &model.CustomGeoResource{
|
|
Type: form.Type,
|
|
Alias: form.Alias,
|
|
Url: form.Url,
|
|
}
|
|
err := a.customGeoService.Create(r)
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastAdd"), mapCustomGeoErr(c, err))
|
|
}
|
|
|
|
func parseCustomGeoID(c *gin.Context, idStr string) (int, bool) {
|
|
id, err := strconv.Atoi(idStr)
|
|
if err != nil {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoInvalidId"), err)
|
|
return 0, false
|
|
}
|
|
if id <= 0 {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoInvalidId"), errors.New(""))
|
|
return 0, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
func (a *CustomGeoController) update(c *gin.Context) {
|
|
id, ok := parseCustomGeoID(c, c.Param("id"))
|
|
if !ok {
|
|
return
|
|
}
|
|
var form customGeoForm
|
|
if bindErr := c.ShouldBind(&form); bindErr != nil {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastUpdate"), bindErr)
|
|
return
|
|
}
|
|
r := &model.CustomGeoResource{
|
|
Type: form.Type,
|
|
Alias: form.Alias,
|
|
Url: form.Url,
|
|
}
|
|
err := a.customGeoService.Update(id, r)
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastUpdate"), mapCustomGeoErr(c, err))
|
|
}
|
|
|
|
func (a *CustomGeoController) delete(c *gin.Context) {
|
|
id, ok := parseCustomGeoID(c, c.Param("id"))
|
|
if !ok {
|
|
return
|
|
}
|
|
name, err := a.customGeoService.Delete(id)
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastDelete", "fileName=="+name), mapCustomGeoErr(c, err))
|
|
}
|
|
|
|
func (a *CustomGeoController) download(c *gin.Context) {
|
|
id, ok := parseCustomGeoID(c, c.Param("id"))
|
|
if !ok {
|
|
return
|
|
}
|
|
name, err := a.customGeoService.TriggerUpdate(id)
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastDownload", "fileName=="+name), mapCustomGeoErr(c, err))
|
|
}
|
|
|
|
func (a *CustomGeoController) updateAll(c *gin.Context) {
|
|
res, err := a.customGeoService.TriggerUpdateAll()
|
|
if err != nil {
|
|
jsonMsg(c, I18nWeb(c, "pages.index.customGeoToastUpdateAll"), mapCustomGeoErr(c, err))
|
|
return
|
|
}
|
|
if len(res.Failed) > 0 {
|
|
c.JSON(http.StatusOK, entity.Msg{
|
|
Success: false,
|
|
Msg: I18nWeb(c, "pages.index.customGeoErrUpdateAllIncomplete"),
|
|
Obj: res,
|
|
})
|
|
return
|
|
}
|
|
jsonMsgObj(c, I18nWeb(c, "pages.index.customGeoToastUpdateAll"), res, nil)
|
|
}
|