From 6bad7f4b5be37667ded240925d56fee91ce3fde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Sat, 13 Jul 2024 01:17:24 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=E5=92=8C=E5=89=8D=E7=AB=AF=E5=8A=A0=E8=BD=BD=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/goreleaser.yml | 3 +- .github/workflows/issue-close-question.yml | 25 ------- .gitignore | 7 +- .gitlab-ci.yml | 5 +- .goreleaser.yaml | 1 - app/http/controllers/asset_controller.go | 77 ---------------------- app/http/controllers/user_controller.go | 7 +- app/http/kernel.go | 2 + app/http/middleware/entrance.go | 38 +++++++++++ app/http/middleware/static.go | 16 +++++ embed/embed.go | 6 ++ go.mod | 1 + go.sum | 2 + routes/api.go | 22 +++---- 14 files changed, 81 insertions(+), 131 deletions(-) delete mode 100644 .github/workflows/issue-close-question.yml delete mode 100644 app/http/controllers/asset_controller.go create mode 100644 app/http/middleware/entrance.go create mode 100644 app/http/middleware/static.go create mode 100644 embed/embed.go diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index 8f068107..d63efbfe 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -21,9 +21,8 @@ jobs: run: | sudo apt-get install -y curl jq unzip zip curl -sSL https://api.github.com/repos/TheTNB/panel-frontend/releases/latest | jq -r ".assets[] | select(.name | contains(\"dist\")) | .browser_download_url" | xargs curl -L -o frontend.zip - rm -rf public unzip frontend.zip - mv dist public + mv dist embed/frontend - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: diff --git a/.github/workflows/issue-close-question.yml b/.github/workflows/issue-close-question.yml deleted file mode 100644 index 89554f01..00000000 --- a/.github/workflows/issue-close-question.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Issue Close Question - -on: - schedule: - - cron: "0 0 * * *" - -permissions: - contents: read - -jobs: - issue-close-require: - permissions: - issues: write - pull-requests: write - runs-on: ubuntu-latest - steps: - - name: needs more info - uses: actions-cool/issues-helper@v3 - with: - actions: 'close-issues' - labels: 'question' - inactive-day: 3 - body: | - 由于该 Issue 3天未收到回应,现已被自动关闭,若有任何问题,可评论回复。 - This issue has been closed automatically because it has not had recent activity for 3 days. If you have any questions, please comment here. diff --git a/.gitignore b/.gitignore index 1edbf21a..d82026ff 100644 --- a/.gitignore +++ b/.gitignore @@ -68,7 +68,6 @@ out/ __debug_bin .project -# 前端工具链 # -.sass-cache/* -node_modules/ -/public +# 嵌入文件 # +embed/* +!embed/embed.go diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c3c3c99c..0f086ae9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -62,13 +62,12 @@ fetch: - apk add --no-cache curl jq unzip zip script: - curl -sSL "https://git.haozi.net/api/v4/projects/opensource%2Fpanel-frontend/releases" | jq -r '.[0].assets.links[] | select(.name | contains("dist")) | .direct_asset_url' | xargs curl -L -o frontend.zip - - rm -rf public - unzip frontend.zip - - mv dist public + - mv dist embed/frontend artifacts: name: "frontend" paths: - - public + - embed/frontend expire_in: 3 days release: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 6551d101..047655f1 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -40,7 +40,6 @@ archives: files: - LICENSE - docs/* - - public/* - storage/* - lang/* - scripts/* diff --git a/app/http/controllers/asset_controller.go b/app/http/controllers/asset_controller.go deleted file mode 100644 index 946d2a20..00000000 --- a/app/http/controllers/asset_controller.go +++ /dev/null @@ -1,77 +0,0 @@ -package controllers - -import ( - "os" - "strings" - - "github.com/goravel/framework/contracts/http" - "github.com/goravel/framework/facades" - - "github.com/TheTNB/panel/internal" - "github.com/TheTNB/panel/internal/services" - "github.com/TheTNB/panel/pkg/io" -) - -type AssetController struct { - setting internal.Setting -} - -func NewAssetController() *AssetController { - return &AssetController{ - setting: services.NewSettingImpl(), - } -} - -func (r *AssetController) Index(ctx http.Context) http.Response { - entrance := facades.Config().GetString("http.entrance") - if entrance == "/" { - entrance = "" - } - - // 自动纠正 URL 格式 - if ctx.Request().Path() == entrance && ctx.Request().Path() != "/" { - return ctx.Response().Redirect(http.StatusMovedPermanently, ctx.Request().Path()+"/") - } - // 拒绝访问非入口文件 - if !strings.HasPrefix(ctx.Request().Path(), entrance) { - return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound)) - } - - path := strings.TrimPrefix(ctx.Request().Path(), entrance) - // 设置默认首页 - if path == "/" || path == "" { - path = "/index.html" - } - - if !io.Exists("public" + path) { - return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound)) - } - - file, err := os.Open("public" + path) - if err != nil { - return Error(ctx, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) - } - - stat, err := file.Stat() - if err != nil { - return Error(ctx, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) - } - - if stat.IsDir() { - return Error(ctx, http.StatusForbidden, http.StatusText(http.StatusForbidden)) - } - - return ctx.Response().Header("Cache-Control", "no-cache").File("public" + path) -} - -func (r *AssetController) Favicon(ctx http.Context) http.Response { - return ctx.Response().File("public/favicon.png") -} - -func (r *AssetController) Robots(ctx http.Context) http.Response { - return ctx.Response().File("public/robots.txt") -} - -func (r *AssetController) NotFound(ctx http.Context) http.Response { - return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound)) -} diff --git a/app/http/controllers/user_controller.go b/app/http/controllers/user_controller.go index f9992b22..881583a9 100644 --- a/app/http/controllers/user_controller.go +++ b/app/http/controllers/user_controller.go @@ -1,8 +1,6 @@ package controllers import ( - "fmt" - "github.com/goravel/framework/contracts/http" "github.com/goravel/framework/facades" "github.com/spf13/cast" @@ -75,10 +73,7 @@ func (r *UserController) Login(ctx http.Context) http.Response { // @Success 200 {object} SuccessResponse // @Router /panel/user/logout [post] func (r *UserController) Logout(ctx http.Context) http.Response { - if err := ctx.Request().Session().Invalidate(); err != nil { - return Error(ctx, http.StatusInternalServerError, fmt.Sprintf("登出失败: %s", err.Error())) - } - + ctx.Request().Session().Forget("user_id") return Success(ctx, nil) } diff --git a/app/http/kernel.go b/app/http/kernel.go index 02c43037..e4c6468c 100644 --- a/app/http/kernel.go +++ b/app/http/kernel.go @@ -17,5 +17,7 @@ func (kernel Kernel) Middleware() []http.Middleware { sessionmiddleware.StartSession(), middleware.Log(), middleware.Status(), + middleware.Entrance(), + middleware.Static(), } } diff --git a/app/http/middleware/entrance.go b/app/http/middleware/entrance.go new file mode 100644 index 00000000..39870585 --- /dev/null +++ b/app/http/middleware/entrance.go @@ -0,0 +1,38 @@ +package middleware + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + "github.com/spf13/cast" +) + +func Entrance() http.Middleware { + return func(ctx http.Context) { + translate := facades.Lang(ctx) + + if !ctx.Request().HasSession() { + ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{ + "message": translate.Get("auth.session.missing"), + }) + return + } + + entrance := facades.Config().GetString("http.entrance") + if ctx.Request().Path() == entrance { + ctx.Request().Session().Put("verify_entrance", true) + ctx.Response().Redirect(http.StatusFound, "/") + return + } + + if !facades.Config().GetBool("app.debug") && + (ctx.Request().Session().Missing("verify_entrance") || !cast.ToBool(ctx.Request().Session().Get("verify_entrance"))) && + ctx.Request().Path() != "/robots.txt" { + ctx.Request().AbortWithStatusJson(http.StatusTeapot, http.Json{ + "message": "请通过正确的入口访问", + }) + return + } + + ctx.Request().Next() + } +} diff --git a/app/http/middleware/static.go b/app/http/middleware/static.go new file mode 100644 index 00000000..b8f588a3 --- /dev/null +++ b/app/http/middleware/static.go @@ -0,0 +1,16 @@ +package middleware + +import ( + "github.com/gin-contrib/static" + "github.com/goravel/framework/contracts/http" + "github.com/goravel/gin" + + "github.com/TheTNB/panel/embed" +) + +func Static() http.Middleware { + return func(ctx http.Context) { + static.Serve("/", static.EmbedFolder(embed.PublicFS, "frontend"))(ctx.(*gin.Context).Instance()) + ctx.Request().Next() + } +} diff --git a/embed/embed.go b/embed/embed.go new file mode 100644 index 00000000..463ef65c --- /dev/null +++ b/embed/embed.go @@ -0,0 +1,6 @@ +package embed + +import "embed" + +//go:embed public/* +var PublicFS embed.FS diff --git a/go.mod b/go.mod index cd900cb3..859d2b9e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.22 require ( github.com/docker/docker v27.0.3+incompatible github.com/docker/go-connections v0.5.0 + github.com/gin-contrib/static v1.1.2 github.com/go-gormigrate/gormigrate/v2 v2.1.2 github.com/go-resty/resty/v2 v2.13.1 github.com/go-sql-driver/mysql v1.8.1 diff --git a/go.sum b/go.sum index 4e5b080e..4e00c36b 100644 --- a/go.sum +++ b/go.sum @@ -165,6 +165,8 @@ github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSe github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4= +github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= diff --git a/routes/api.go b/routes/api.go index a188f21c..8feea521 100644 --- a/routes/api.go +++ b/routes/api.go @@ -1,12 +1,16 @@ package routes import ( + "path/filepath" + + "github.com/goravel/framework/contracts/http" "github.com/goravel/framework/contracts/route" "github.com/goravel/framework/facades" frameworkmiddleware "github.com/goravel/framework/http/middleware" "github.com/TheTNB/panel/app/http/controllers" "github.com/TheTNB/panel/app/http/middleware" + "github.com/TheTNB/panel/embed" ) func Api() { @@ -221,17 +225,9 @@ func Api() { swaggerController := controllers.NewSwaggerController() facades.Route().Middleware(middleware.Session()).Get("swagger/*any", swaggerController.Index) - // 静态文件 - entrance := facades.Config().GetString("http.entrance") - if entrance == "/" { - entrance = "" - } - assetController := controllers.NewAssetController() - facades.Route().Get("favicon.png", assetController.Favicon) - facades.Route().Get("robots.txt", assetController.Robots) - facades.Route().Get(entrance+"/assets/{any}", assetController.Index) - facades.Route().Get(entrance+"/loading/{any}", assetController.Index) - facades.Route().Get(entrance+"/{any}", assetController.Index) - facades.Route().Get(entrance+"/", assetController.Index) - facades.Route().Fallback(assetController.NotFound) + // 404 + facades.Route().Fallback(func(ctx http.Context) http.Response { + index, _ := embed.PublicFS.ReadFile(filepath.Join("public", "index.html")) + return ctx.Response().Data(http.StatusOK, "text/html; charset=utf-8", index) + }) }