diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07b3944..9af04e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,49 +25,18 @@ jobs: container: image: goreleaser/goreleaser-cross:v1.23 steps: + - run: | + apt update && apt install unzip curl -y + wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + chmod +x /usr/bin/yq + - run: git config --global --add safe.directory /__w/nezha/nezha - uses: actions/checkout@v4 - - name: clean cache + - name: Prepare frontends' dists run: | - rm -rf cmd/dashboard/*-dist - - - uses: robinraju/release-downloader@v1 - with: - repository: nezhahq/admin-frontend - tag: v1.1.1 - fileName: dist.zip - latest: true - extract: true - - - name: prepare admin-frontend dists - run: | - mv dist cmd/dashboard/admin-dist - - - uses: robinraju/release-downloader@v1 - with: - repository: nezhahq/user-frontend - tag: v1.1.1 - fileName: dist.zip - latest: true - extract: true - - - name: prepare admin-frontend dists - run: | - mv dist cmd/dashboard/user-dist - - - uses: robinraju/release-downloader@v1 - with: - repository: hi2shark/nazhua - tag: v0.4.9 - fileName: dist.zip - latest: true - extract: true - - - name: prepare nazhua-frontend dists - run: | - mv dist cmd/dashboard/nazhua-dist + chmod +x ./script/fetch-frontends.sh && ./script/fetch-frontends.sh - name: Fetch IPInfo GeoIP Database env: diff --git a/.gitignore b/.gitignore index c3b8b90..fb3e1c7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,8 +17,7 @@ .DS_Store /cmd/dashboard/data /cmd/dashboard/main -/cmd/dashboard/admin-dist/* -/cmd/dashboard/user-dist/* +/cmd/dashboard/*-dist !/cmd/dashboard/admin-dist/.gitkeep !/cmd/dashboard/user-dist/.gitkeep /config.yml diff --git a/cmd/dashboard/controller/setting.go b/cmd/dashboard/controller/setting.go index 6b83a60..ef3a1b4 100644 --- a/cmd/dashboard/controller/setting.go +++ b/cmd/dashboard/controller/setting.go @@ -23,9 +23,9 @@ func listConfig(c *gin.Context) (model.SettingResponse, error) { authorized := isMember // TODO || isViewPasswordVerfied conf := model.SettingResponse{ - Config: *singleton.Conf, - Version: singleton.Version, - UserTemplates: singleton.UserTemplates, + Config: *singleton.Conf, + Version: singleton.Version, + FrontendTemplates: singleton.FrontendTemplates, } if !authorized { @@ -59,8 +59,8 @@ func updateConfig(c *gin.Context) (any, error) { return nil, err } var userTemplateValid bool - for _, v := range singleton.UserTemplates { - if v.Path == sf.UserTemplate { + for _, v := range singleton.FrontendTemplates { + if v.Path == sf.UserTemplate && sf.UserTemplate != "admin-dist" { userTemplateValid = true break } diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index f0c216a..2664366 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -104,6 +104,7 @@ func main() { } // 初始化 dao 包 + singleton.InitFrontendTemplates() singleton.InitConfigFromPath(dashboardCliParam.ConfigFile) singleton.InitTimezoneAndCache() singleton.InitDBFromPath(dashboardCliParam.DatebaseLocation) diff --git a/model/config.go b/model/config.go index ed9b964..ce839d4 100644 --- a/model/config.go +++ b/model/config.go @@ -56,7 +56,7 @@ type Config struct { } // Read 读取配置文件并应用 -func (c *Config) Read(path string, userTemplates []UserTemplate) error { +func (c *Config) Read(path string, frontendTemplates []FrontendTemplate) error { c.k = koanf.New(".") c.filePath = path @@ -89,8 +89,8 @@ func (c *Config) Read(path string, userTemplates []UserTemplate) error { c.Location = "Asia/Shanghai" } var userTemplateValid bool - for _, v := range userTemplates { - if v.Path == c.UserTemplate { + for _, v := range frontendTemplates { + if v.Path == c.UserTemplate && c.UserTemplate != "admin-dist" { userTemplateValid = true break } diff --git a/model/setting_api.go b/model/setting_api.go index cc78fb3..db3dbcb 100644 --- a/model/setting_api.go +++ b/model/setting_api.go @@ -18,17 +18,19 @@ type SettingForm struct { EnablePlainIPInNotification bool `json:"enable_plain_ip_in_notification,omitempty" validate:"optional"` } -type UserTemplate struct { +type FrontendTemplate struct { Path string `json:"path,omitempty"` Name string `json:"name,omitempty"` Repository string `json:"repository,omitempty"` Author string `json:"author,omitempty"` Community bool `json:"community,omitempty"` + Version string `json:"version,omitempty"` + IsAdmin string `json:"is_admin,omitempty"` } type SettingResponse struct { Config - Version string `json:"version,omitempty"` - UserTemplates []UserTemplate `json:"user_templates,omitempty"` + Version string `json:"version,omitempty"` + FrontendTemplates []FrontendTemplate `json:"frontend_templates,omitempty"` } diff --git a/script/fetch-frontends.sh b/script/fetch-frontends.sh new file mode 100755 index 0000000..1dbb644 --- /dev/null +++ b/script/fetch-frontends.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -euo pipefail + +ROOT_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")/..")" +TEMPLATES_FILE="$ROOT_DIR/service/singleton/frontend-templates.yaml" + +download_and_extract() { + local repository="$1" + local version="$2" + local targetDir="$3" + local TMP_DIR + + TMP_DIR="$(mktemp -d)" + + echo "Downloading from repository: $repository, version: $version" + + pushd "$TMP_DIR" || exit + + curl -L -o "dist.zip" "$repository/releases/download/$version/dist.zip" + + [ -e "$targetDir" ] && rm -r "$targetDir" + unzip -q dist.zip + mv dist "$targetDir" + + rm "dist.zip" + popd || exit +} + +count=$(yq eval '. | length' "$TEMPLATES_FILE") + +for i in $(seq 0 $(("$count"-1))); do + path=$(yq -r ".[$i].path" "$TEMPLATES_FILE") + repository=$(yq -r ".[$i].repository" "$TEMPLATES_FILE") + version=$(yq -r ".[$i].version" "$TEMPLATES_FILE") + + if [[ -n $path && -n $repository && -n $version ]]; then + download_and_extract "$repository" "$version" "$ROOT_DIR/cmd/dashboard/$path" + fi +done diff --git a/service/singleton/frontend-templates.yaml b/service/singleton/frontend-templates.yaml new file mode 100644 index 0000000..d4e5a07 --- /dev/null +++ b/service/singleton/frontend-templates.yaml @@ -0,0 +1,17 @@ +- path: "admin-dist" + name: "OfficialAdmin" + repository: "https://github.com/nezhahq/admin-frontend" + author: "nezhahq" + version: "v1.1.1" + isadmin: true +- path: "user-dist" + name: "Official" + repository: "https://github.com/hamster1963/nezha-dash-v1" + author: "hamster1963" + version: "v1.2.5" +- path: "nazhua-dist" + name: "Nazhua" + repository: "https://github.com/hi2shark/nazhua" + author: "hi2hi" + version: "v0.4.10" + community: true diff --git a/service/singleton/singleton.go b/service/singleton/singleton.go index 2f155fe..0d2bedb 100644 --- a/service/singleton/singleton.go +++ b/service/singleton/singleton.go @@ -1,10 +1,12 @@ package singleton import ( + _ "embed" "log" "time" "github.com/patrickmn/go-cache" + "gopkg.in/yaml.v3" "gorm.io/driver/sqlite" "gorm.io/gorm" @@ -15,27 +17,17 @@ import ( var Version = "debug" var ( - Conf *model.Config - Cache *cache.Cache - DB *gorm.DB - Loc *time.Location - UserTemplates = []model.UserTemplate{ - { - Path: "user-dist", - Name: "Official", - Repository: "https://github.com/hamster1963/nezha-dash", - Author: "hamster1963", - }, { - Path: "nazhua-dist", - Name: "Nazhua", - Repository: "https://github.com/hi2shark/nazhua", - Author: "hi2hi", - Community: true, - }, - } + Conf *model.Config + Cache *cache.Cache + DB *gorm.DB + Loc *time.Location + FrontendTemplates []model.FrontendTemplate DashboardBootTime = uint64(time.Now().Unix()) ) +//go:embed frontend-templates.yaml +var frontendTemplatesYAML []byte + func InitTimezoneAndCache() { var err error Loc, err = time.LoadLocation(Conf.Location) @@ -56,10 +48,18 @@ func LoadSingleton() { initDDNS() } +// InitFrontendTemplates 从内置文件中加载FrontendTemplates +func InitFrontendTemplates() { + err := yaml.Unmarshal(frontendTemplatesYAML, &FrontendTemplates) + if err != nil { + panic(err) + } +} + // InitConfigFromPath 从给出的文件路径中加载配置 func InitConfigFromPath(path string) { Conf = &model.Config{} - err := Conf.Read(path, UserTemplates) + err := Conf.Read(path, FrontendTemplates) if err != nil { panic(err) }