Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'web/controller')
-rw-r--r--web/controller/api.go8
-rw-r--r--web/controller/custom_geo.go174
-rw-r--r--web/controller/util.go13
3 files changed, 190 insertions, 5 deletions
diff --git a/web/controller/api.go b/web/controller/api.go
index 1a39f8ed..57d2e4cb 100644
--- a/web/controller/api.go
+++ b/web/controller/api.go
@@ -18,9 +18,9 @@ type APIController struct {
}
// NewAPIController creates a new APIController instance and initializes its routes.
-func NewAPIController(g *gin.RouterGroup) *APIController {
+func NewAPIController(g *gin.RouterGroup, customGeo *service.CustomGeoService) *APIController {
a := &APIController{}
- a.initRouter(g)
+ a.initRouter(g, customGeo)
return a
}
@@ -35,7 +35,7 @@ func (a *APIController) checkAPIAuth(c *gin.Context) {
}
// initRouter sets up the API routes for inbounds, server, and other endpoints.
-func (a *APIController) initRouter(g *gin.RouterGroup) {
+func (a *APIController) initRouter(g *gin.RouterGroup, customGeo *service.CustomGeoService) {
// Main API group
api := g.Group("/panel/api")
api.Use(a.checkAPIAuth)
@@ -48,6 +48,8 @@ func (a *APIController) initRouter(g *gin.RouterGroup) {
server := api.Group("/server")
a.serverController = NewServerController(server)
+ NewCustomGeoController(api.Group("/custom-geo"), customGeo)
+
// Extra routes
api.GET("/backuptotgbot", a.BackuptoTgbot)
}
diff --git a/web/controller/custom_geo.go b/web/controller/custom_geo.go
new file mode 100644
index 00000000..b0542581
--- /dev/null
+++ b/web/controller/custom_geo.go
@@ -0,0 +1,174 @@
+package controller
+
+import (
+ "errors"
+ "net/http"
+ "strconv"
+
+ "github.com/mhsanaei/3x-ui/v2/database/model"
+ "github.com/mhsanaei/3x-ui/v2/logger"
+ "github.com/mhsanaei/3x-ui/v2/web/entity"
+ "github.com/mhsanaei/3x-ui/v2/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"))
+ 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)
+}
diff --git a/web/controller/util.go b/web/controller/util.go
index b11203bd..3d266f29 100644
--- a/web/controller/util.go
+++ b/web/controller/util.go
@@ -50,8 +50,17 @@ func jsonMsgObj(c *gin.Context, msg string, obj any, err error) {
}
} else {
m.Success = false
- m.Msg = msg + " (" + err.Error() + ")"
- logger.Warning(msg+" "+I18nWeb(c, "fail")+": ", err)
+ errStr := err.Error()
+ if errStr != "" {
+ m.Msg = msg + " (" + errStr + ")"
+ logger.Warning(msg+" "+I18nWeb(c, "fail")+": ", err)
+ } else if msg != "" {
+ m.Msg = msg
+ logger.Warning(msg + " " + I18nWeb(c, "fail"))
+ } else {
+ m.Msg = I18nWeb(c, "somethingWentWrong")
+ logger.Warning(I18nWeb(c, "somethingWentWrong") + " " + I18nWeb(c, "fail"))
+ }
}
c.JSON(http.StatusOK, m)
}