Merge branch 'master' into l10n_master
This commit is contained in:
		
						commit
						71018b545c
					
				@ -4,7 +4,7 @@
 | 
				
			|||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
 | 
					  <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
 | 
				
			||||||
  <br><br>
 | 
					  <br><br>
 | 
				
			||||||
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.12.30&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.9.0-brightgreen?style=for-the-badge&logo=linux">
 | 
					<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.13.1&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.9.1-brightgreen?style=for-the-badge&logo=linux"> <a title="Crowdin" target="_blank" href="https://crowdin.com/project/nezha"><img src="https://badges.crowdin.net/nezha/localized.svg"></a>
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <p>:trollface: <b>Nezha Monitoring</b> One-stop light monitoring and light operation and maintenance system. Supports system status, HTTP (SSL certificate change, upcoming expiration, expiration), TCP, Ping monitoring and alarm, scheduled tasks and web terminal.</p>
 | 
					  <p>:trollface: <b>Nezha Monitoring</b> One-stop light monitoring and light operation and maintenance system. Supports system status, HTTP (SSL certificate change, upcoming expiration, expiration), TCP, Ping monitoring and alarm, scheduled tasks and web terminal.</p>
 | 
				
			||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
\>> QQ 交流群:872069346 **加群要求:已搭建好哪吒监控 & 有 2+ 服务器, 机器人自动审核**
 | 
					\>> QQ 交流群:872069346 **加群要求:已搭建好哪吒监控 & 有 2+ 服务器, 机器人自动审核**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\>> [Use Cases | 我们的用户](https://www.google.com/search?q="powered+by+哪吒监控"&filter=0) (Google)
 | 
					\>> [Use Cases | 我们的用户](https://www.google.com/search?q=%22powered+by+%E5%93%AA%E5%90%92%E7%9B%91%E6%8E%A7%22+OR+%22powered+by+Nezha+Monitoring%22&filter=0) (Google)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Default Theme                                                                                 | DayNight [@JackieSung](https://github.com/JackieSung4ev)                                               | hotaru                                                                     |
 | 
					| Default Theme                                                                                 | DayNight [@JackieSung](https://github.com/JackieSung4ev)                                               | hotaru                                                                     |
 | 
				
			||||||
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
 | 
					| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
 | 
				
			||||||
@ -25,7 +25,7 @@
 | 
				
			|||||||
## User Guide
 | 
					## User Guide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [中文文档](docs/UserGuide_zh.md)
 | 
					- [中文文档](docs/UserGuide_zh.md)
 | 
				
			||||||
- [English](docs/UserGuide_en.md)
 | 
					- [English](docs/UserGuide_en.md) WIP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Special Thanks
 | 
					## Special Thanks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,6 +33,6 @@
 | 
				
			|||||||
- [@Erope](https://github.com/JackieSung4ev) for contributed a lot to our installation scripts and community building.
 | 
					- [@Erope](https://github.com/JackieSung4ev) for contributed a lot to our installation scripts and community building.
 | 
				
			||||||
- [@MikoyChinese](https://github.com/MikoyChinese) for our second community-contributed front-end theme.
 | 
					- [@MikoyChinese](https://github.com/MikoyChinese) for our second community-contributed front-end theme.
 | 
				
			||||||
- [@AkkiaS7](https://github.com/Akkia) and [hhhkkk520](https://github.com/hhhkkk520) for the excellent contribution in the early days of globalization.
 | 
					- [@AkkiaS7](https://github.com/Akkia) and [hhhkkk520](https://github.com/hhhkkk520) for the excellent contribution in the early days of globalization.
 | 
				
			||||||
- [@dysf888](https://gitub.com/dysf888) for the installation script in windows.
 | 
					- [@dysf888](https://gitub.com/dysf888) for the installation script in Windows.
 | 
				
			||||||
- [@MartijnLindeman](https://github.com/MartijnLindeman) for his perseverance has taken us to the international market.
 | 
					- [@MartijnLindeman](https://github.com/MartijnLindeman) for his perseverance has taken us to the international market.
 | 
				
			||||||
- and other [contributors](https://github.com/naiba/nezha/graphs/contributors).
 | 
					- and other [contributors](https://github.com/naiba/nezha/graphs/contributors).
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,6 @@ package controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
@ -14,6 +13,7 @@ import (
 | 
				
			|||||||
	"github.com/gorilla/websocket"
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
	"github.com/hashicorp/go-uuid"
 | 
						"github.com/hashicorp/go-uuid"
 | 
				
			||||||
	"github.com/jinzhu/copier"
 | 
						"github.com/jinzhu/copier"
 | 
				
			||||||
 | 
						"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
				
			||||||
	"golang.org/x/crypto/bcrypt"
 | 
						"golang.org/x/crypto/bcrypt"
 | 
				
			||||||
	"golang.org/x/sync/singleflight"
 | 
						"golang.org/x/sync/singleflight"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -60,7 +60,7 @@ func (p *commonPage) issueViewPassword(c *gin.Context) {
 | 
				
			|||||||
	err := c.ShouldBind(&vpf)
 | 
						err := c.ShouldBind(&vpf)
 | 
				
			||||||
	var hash []byte
 | 
						var hash []byte
 | 
				
			||||||
	if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword {
 | 
						if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword {
 | 
				
			||||||
		err = errors.New("查看密码错误")
 | 
							err = errors.New(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "WrongAccessPassword"}))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		hash, err = bcrypt.GenerateFromPassword([]byte(vpf.Password), bcrypt.DefaultCost)
 | 
							hash, err = bcrypt.GenerateFromPassword([]byte(vpf.Password), bcrypt.DefaultCost)
 | 
				
			||||||
@ -68,8 +68,10 @@ func (p *commonPage) issueViewPassword(c *gin.Context) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
							mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
				
			||||||
			Code: http.StatusOK,
 | 
								Code: http.StatusOK,
 | 
				
			||||||
			Title: "出现错误",
 | 
								Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
				
			||||||
			Msg:   fmt.Sprintf("请求错误:%s", err),
 | 
									MessageID: "AnErrorEccurred",
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
 | 
								Msg: err.Error(),
 | 
				
			||||||
		}, true)
 | 
							}, true)
 | 
				
			||||||
		c.Abort()
 | 
							c.Abort()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@ -92,7 +94,7 @@ func (p *commonPage) checkViewPassword(c *gin.Context) {
 | 
				
			|||||||
	viewPassword, _ := c.Cookie(singleton.Conf.Site.CookieName + "-vp")
 | 
						viewPassword, _ := c.Cookie(singleton.Conf.Site.CookieName + "-vp")
 | 
				
			||||||
	if err := bcrypt.CompareHashAndPassword([]byte(viewPassword), []byte(singleton.Conf.Site.ViewPassword)); err != nil {
 | 
						if err := bcrypt.CompareHashAndPassword([]byte(viewPassword), []byte(singleton.Conf.Site.ViewPassword)); err != nil {
 | 
				
			||||||
		c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/viewpassword", mygin.CommonEnvironment(c, gin.H{
 | 
							c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/viewpassword", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
			"Title":      "验证查看密码",
 | 
								"Title":      singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "VerifyPassword"}),
 | 
				
			||||||
			"CustomCode": singleton.Conf.Site.CustomCode,
 | 
								"CustomCode": singleton.Conf.Site.CustomCode,
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
		c.Abort()
 | 
							c.Abort()
 | 
				
			||||||
@ -116,7 +118,7 @@ func (p *commonPage) service(c *gin.Context) {
 | 
				
			|||||||
		}, nil
 | 
							}, nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/service", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/service", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title":              "服务状态",
 | 
							"Title":              singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesStatus"}),
 | 
				
			||||||
		"Services":           res.([]interface{})[0],
 | 
							"Services":           res.([]interface{})[0],
 | 
				
			||||||
		"CycleTransferStats": res.([]interface{})[1],
 | 
							"CycleTransferStats": res.([]interface{})[1],
 | 
				
			||||||
		"CustomCode":         singleton.Conf.Site.CustomCode,
 | 
							"CustomCode":         singleton.Conf.Site.CustomCode,
 | 
				
			||||||
@ -140,7 +142,9 @@ func (cp *commonPage) home(c *gin.Context) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
							mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
				
			||||||
			Code: http.StatusInternalServerError,
 | 
								Code: http.StatusInternalServerError,
 | 
				
			||||||
			Title: "系统错误",
 | 
								Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
				
			||||||
 | 
									MessageID: "SystemError",
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
			Msg:  "服务器状态获取失败",
 | 
								Msg:  "服务器状态获取失败",
 | 
				
			||||||
			Link: "/",
 | 
								Link: "/",
 | 
				
			||||||
			Btn:  "返回首页",
 | 
								Btn:  "返回首页",
 | 
				
			||||||
@ -168,7 +172,9 @@ func (cp *commonPage) ws(c *gin.Context) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
							mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
				
			||||||
			Code: http.StatusInternalServerError,
 | 
								Code: http.StatusInternalServerError,
 | 
				
			||||||
			Title: "网络错误",
 | 
								Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
				
			||||||
 | 
									MessageID: "NetowrkError",
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
			Msg:  "Websocket协议切换失败",
 | 
								Msg:  "Websocket协议切换失败",
 | 
				
			||||||
			Link: "/",
 | 
								Link: "/",
 | 
				
			||||||
			Btn:  "返回首页",
 | 
								Btn:  "返回首页",
 | 
				
			||||||
@ -313,7 +319,9 @@ func (cp *commonPage) terminal(c *gin.Context) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
							mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
				
			||||||
			Code: http.StatusInternalServerError,
 | 
								Code: http.StatusInternalServerError,
 | 
				
			||||||
			Title: "网络错误",
 | 
								Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
				
			||||||
 | 
									MessageID: "NetowrkError",
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
			Msg:  "Websocket协议切换失败",
 | 
								Msg:  "Websocket协议切换失败",
 | 
				
			||||||
			Link: "/",
 | 
								Link: "/",
 | 
				
			||||||
			Btn:  "返回首页",
 | 
								Btn:  "返回首页",
 | 
				
			||||||
@ -448,7 +456,9 @@ func (cp *commonPage) createTerminal(c *gin.Context) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
							mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
				
			||||||
			Code: http.StatusInternalServerError,
 | 
								Code: http.StatusInternalServerError,
 | 
				
			||||||
			Title: "系统错误",
 | 
								Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
				
			||||||
 | 
									MessageID: "SystemError",
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
			Msg:  "生成会话ID失败",
 | 
								Msg:  "生成会话ID失败",
 | 
				
			||||||
			Link: "/server",
 | 
								Link: "/server",
 | 
				
			||||||
			Btn:  "返回重试",
 | 
								Btn:  "返回重试",
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,49 @@ func ServeWeb(port uint) *http.Server {
 | 
				
			|||||||
		pprof.Register(r)
 | 
							pprof.Register(r)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r.Use(mygin.RecordPath)
 | 
						r.Use(mygin.RecordPath)
 | 
				
			||||||
	r.SetFuncMap(template.FuncMap{
 | 
						r.SetFuncMap(funcMap)
 | 
				
			||||||
 | 
						r.Static("/static", "resource/static")
 | 
				
			||||||
 | 
						r.LoadHTMLGlob("resource/template/**/*.html")
 | 
				
			||||||
 | 
						routers(r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page404 := func(c *gin.Context) {
 | 
				
			||||||
 | 
							mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
				
			||||||
 | 
								Code:  http.StatusNotFound,
 | 
				
			||||||
 | 
								Title: "该页面不存在",
 | 
				
			||||||
 | 
								Msg:   "该页面内容可能已着陆火星",
 | 
				
			||||||
 | 
								Link:  "/",
 | 
				
			||||||
 | 
								Btn:   "返回首页",
 | 
				
			||||||
 | 
							}, true)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						r.NoRoute(page404)
 | 
				
			||||||
 | 
						r.NoMethod(page404)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv := &http.Server{
 | 
				
			||||||
 | 
							Addr:    fmt.Sprintf(":%d", port),
 | 
				
			||||||
 | 
							Handler: r,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func routers(r *gin.Engine) {
 | 
				
			||||||
 | 
						// 通用页面
 | 
				
			||||||
 | 
						cp := commonPage{r: r, terminals: make(map[string]*terminalContext), terminalsLock: new(sync.Mutex)}
 | 
				
			||||||
 | 
						cp.serve()
 | 
				
			||||||
 | 
						// 游客页面
 | 
				
			||||||
 | 
						gp := guestPage{r}
 | 
				
			||||||
 | 
						gp.serve()
 | 
				
			||||||
 | 
						// 会员页面
 | 
				
			||||||
 | 
						mp := &memberPage{r}
 | 
				
			||||||
 | 
						mp.serve()
 | 
				
			||||||
 | 
						// API
 | 
				
			||||||
 | 
						api := r.Group("api")
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ma := &memberAPI{api}
 | 
				
			||||||
 | 
							ma.serve()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var funcMap = template.FuncMap{
 | 
				
			||||||
	"tr": func(id string, dataAndCount ...interface{}) string {
 | 
						"tr": func(id string, dataAndCount ...interface{}) string {
 | 
				
			||||||
		conf := i18n.LocalizeConfig{
 | 
							conf := i18n.LocalizeConfig{
 | 
				
			||||||
			MessageID: id,
 | 
								MessageID: id,
 | 
				
			||||||
@ -135,44 +177,4 @@ func ServeWeb(port uint) *http.Server {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return "故障"
 | 
							return "故障"
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	r.Static("/static", "resource/static")
 | 
					 | 
				
			||||||
	r.LoadHTMLGlob("resource/template/**/*.html")
 | 
					 | 
				
			||||||
	routers(r)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	page404 := func(c *gin.Context) {
 | 
					 | 
				
			||||||
		mygin.ShowErrorPage(c, mygin.ErrInfo{
 | 
					 | 
				
			||||||
			Code:  http.StatusNotFound,
 | 
					 | 
				
			||||||
			Title: "该页面不存在",
 | 
					 | 
				
			||||||
			Msg:   "该页面内容可能已着陆火星",
 | 
					 | 
				
			||||||
			Link:  "/",
 | 
					 | 
				
			||||||
			Btn:   "返回首页",
 | 
					 | 
				
			||||||
		}, true)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	r.NoRoute(page404)
 | 
					 | 
				
			||||||
	r.NoMethod(page404)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &http.Server{
 | 
					 | 
				
			||||||
		Addr:    fmt.Sprintf(":%d", port),
 | 
					 | 
				
			||||||
		Handler: r,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return srv
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func routers(r *gin.Engine) {
 | 
					 | 
				
			||||||
	// 通用页面
 | 
					 | 
				
			||||||
	cp := commonPage{r: r, terminals: make(map[string]*terminalContext), terminalsLock: new(sync.Mutex)}
 | 
					 | 
				
			||||||
	cp.serve()
 | 
					 | 
				
			||||||
	// 游客页面
 | 
					 | 
				
			||||||
	gp := guestPage{r}
 | 
					 | 
				
			||||||
	gp.serve()
 | 
					 | 
				
			||||||
	// 会员页面
 | 
					 | 
				
			||||||
	mp := &memberPage{r}
 | 
					 | 
				
			||||||
	mp.serve()
 | 
					 | 
				
			||||||
	// API
 | 
					 | 
				
			||||||
	api := r.Group("api")
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		ma := &memberAPI{api}
 | 
					 | 
				
			||||||
		ma.serve()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
 | 
						"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/naiba/nezha/model"
 | 
						"github.com/naiba/nezha/model"
 | 
				
			||||||
	"github.com/naiba/nezha/pkg/mygin"
 | 
						"github.com/naiba/nezha/pkg/mygin"
 | 
				
			||||||
@ -40,7 +41,7 @@ func (gp *guestPage) login(c *gin.Context) {
 | 
				
			|||||||
		RegistrationLink = "https://gitee.com/signup"
 | 
							RegistrationLink = "https://gitee.com/signup"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.HTML(http.StatusOK, "dashboard/login", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "dashboard/login", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title":            "登录",
 | 
							"Title":            singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
 | 
				
			||||||
		"LoginType":        LoginType,
 | 
							"LoginType":        LoginType,
 | 
				
			||||||
		"RegistrationLink": RegistrationLink,
 | 
							"RegistrationLink": RegistrationLink,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
 | 
				
			|||||||
@ -551,6 +551,7 @@ func (ma *memberAPI) logout(c *gin.Context) {
 | 
				
			|||||||
type settingForm struct {
 | 
					type settingForm struct {
 | 
				
			||||||
	Title                   string
 | 
						Title                   string
 | 
				
			||||||
	Admin                   string
 | 
						Admin                   string
 | 
				
			||||||
 | 
						Language                string
 | 
				
			||||||
	Theme                   string
 | 
						Theme                   string
 | 
				
			||||||
	CustomCode              string
 | 
						CustomCode              string
 | 
				
			||||||
	ViewPassword            string
 | 
						ViewPassword            string
 | 
				
			||||||
@ -572,6 +573,7 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						singleton.Conf.Language = sf.Language
 | 
				
			||||||
	singleton.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification == "on"
 | 
						singleton.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification == "on"
 | 
				
			||||||
	singleton.Conf.EnablePlainIPInNotification = sf.EnablePlainIPInNotification == "on"
 | 
						singleton.Conf.EnablePlainIPInNotification = sf.EnablePlainIPInNotification == "on"
 | 
				
			||||||
	singleton.Conf.Cover = sf.Cover
 | 
						singleton.Conf.Cover = sf.Cover
 | 
				
			||||||
@ -594,6 +596,8 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// 更新系统语言
 | 
				
			||||||
 | 
						singleton.InitLocalizer()
 | 
				
			||||||
	c.JSON(http.StatusOK, model.Response{
 | 
						c.JSON(http.StatusOK, model.Response{
 | 
				
			||||||
		Code: http.StatusOK,
 | 
							Code: http.StatusOK,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"github.com/naiba/nezha/model"
 | 
						"github.com/naiba/nezha/model"
 | 
				
			||||||
	"github.com/naiba/nezha/pkg/mygin"
 | 
						"github.com/naiba/nezha/pkg/mygin"
 | 
				
			||||||
	"github.com/naiba/nezha/service/singleton"
 | 
						"github.com/naiba/nezha/service/singleton"
 | 
				
			||||||
 | 
						"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type memberPage struct {
 | 
					type memberPage struct {
 | 
				
			||||||
@ -18,8 +19,8 @@ func (mp *memberPage) serve() {
 | 
				
			|||||||
	mr.Use(mygin.Authorize(mygin.AuthorizeOption{
 | 
						mr.Use(mygin.Authorize(mygin.AuthorizeOption{
 | 
				
			||||||
		Member:   true,
 | 
							Member:   true,
 | 
				
			||||||
		IsPage:   true,
 | 
							IsPage:   true,
 | 
				
			||||||
		Msg:      "此页面需要登录",
 | 
							Msg:      singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "YouAreNotAuthorized"}),
 | 
				
			||||||
		Btn:      "点此登录",
 | 
							Btn:      singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
 | 
				
			||||||
		Redirect: "/login",
 | 
							Redirect: "/login",
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	mr.GET("/server", mp.server)
 | 
						mr.GET("/server", mp.server)
 | 
				
			||||||
@ -33,14 +34,14 @@ func (mp *memberPage) server(c *gin.Context) {
 | 
				
			|||||||
	singleton.SortedServerLock.RLock()
 | 
						singleton.SortedServerLock.RLock()
 | 
				
			||||||
	defer singleton.SortedServerLock.RUnlock()
 | 
						defer singleton.SortedServerLock.RUnlock()
 | 
				
			||||||
	c.HTML(http.StatusOK, "dashboard/server", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "dashboard/server", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title":   "服务器管理",
 | 
							"Title":   singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServersManagement"}),
 | 
				
			||||||
		"Servers": singleton.SortedServerList,
 | 
							"Servers": singleton.SortedServerList,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (mp *memberPage) monitor(c *gin.Context) {
 | 
					func (mp *memberPage) monitor(c *gin.Context) {
 | 
				
			||||||
	c.HTML(http.StatusOK, "dashboard/monitor", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "dashboard/monitor", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title":    "服务监控",
 | 
							"Title":    singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
 | 
				
			||||||
		"Monitors": singleton.ServiceSentinelShared.Monitors(),
 | 
							"Monitors": singleton.ServiceSentinelShared.Monitors(),
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -49,7 +50,7 @@ func (mp *memberPage) cron(c *gin.Context) {
 | 
				
			|||||||
	var crons []model.Cron
 | 
						var crons []model.Cron
 | 
				
			||||||
	singleton.DB.Find(&crons)
 | 
						singleton.DB.Find(&crons)
 | 
				
			||||||
	c.HTML(http.StatusOK, "dashboard/cron", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "dashboard/cron", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title": "计划任务",
 | 
							"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
 | 
				
			||||||
		"Crons": crons,
 | 
							"Crons": crons,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -60,7 +61,7 @@ func (mp *memberPage) notification(c *gin.Context) {
 | 
				
			|||||||
	var ar []model.AlertRule
 | 
						var ar []model.AlertRule
 | 
				
			||||||
	singleton.DB.Find(&ar)
 | 
						singleton.DB.Find(&ar)
 | 
				
			||||||
	c.HTML(http.StatusOK, "dashboard/notification", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "dashboard/notification", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title":         "报警通知",
 | 
							"Title":         singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Notification"}),
 | 
				
			||||||
		"Notifications": nf,
 | 
							"Notifications": nf,
 | 
				
			||||||
		"AlertRules":    ar,
 | 
							"AlertRules":    ar,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
@ -68,6 +69,6 @@ func (mp *memberPage) notification(c *gin.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (mp *memberPage) setting(c *gin.Context) {
 | 
					func (mp *memberPage) setting(c *gin.Context) {
 | 
				
			||||||
	c.HTML(http.StatusOK, "dashboard/setting", mygin.CommonEnvironment(c, gin.H{
 | 
						c.HTML(http.StatusOK, "dashboard/setting", mygin.CommonEnvironment(c, gin.H{
 | 
				
			||||||
		"Title": "系统设置",
 | 
							"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -108,7 +108,7 @@ func (oa *oauth2controller) callback(c *gin.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	var isAdmin bool
 | 
						var isAdmin bool
 | 
				
			||||||
	for _, admin := range strings.Split(singleton.Conf.Oauth2.Admin, ",") {
 | 
						for _, admin := range strings.Split(singleton.Conf.Oauth2.Admin, ",") {
 | 
				
			||||||
		if admin != "" && gu.GetLogin() == admin {
 | 
							if admin != "" && strings.ToLower(gu.GetLogin()) == strings.ToLower(admin) {
 | 
				
			||||||
			isAdmin = true
 | 
								isAdmin = true
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,51 +1,5 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/naiba/nezha/service/singleton"
 | 
					 | 
				
			||||||
	"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
					 | 
				
			||||||
	"golang.org/x/text/language"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func htmlTemplateTranslateFn(id string, data interface{}, count interface{}) string {
 | 
					 | 
				
			||||||
	return singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
					 | 
				
			||||||
		MessageID:    id,
 | 
					 | 
				
			||||||
		TemplateData: data,
 | 
					 | 
				
			||||||
		PluralCount:  count,
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	singleton.InitConfigFromPath("data/config.yaml")
 | 
					 | 
				
			||||||
	singleton.InitLocalizer()
 | 
					 | 
				
			||||||
	fmt.Println(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
					 | 
				
			||||||
		MessageID: "nezhaMonitor",
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fmt.Println(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
					 | 
				
			||||||
		MessageID: "nezhaMonitor",
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fmt.Println("tr nezhaMonitor", htmlTemplateTranslateFn("nezhaMonitor", nil, nil))
 | 
					 | 
				
			||||||
	fmt.Println("tr nezhaMonitor", htmlTemplateTranslateFn("nezhaMonitor", nil, 2))
 | 
					 | 
				
			||||||
	fmt.Println("tr nezhaMonitor", htmlTemplateTranslateFn("nezhaMonitor", map[string]string{
 | 
					 | 
				
			||||||
		"Ext": "Plus",
 | 
					 | 
				
			||||||
	}, 2))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bundle := i18n.NewBundle(language.English)
 | 
					 | 
				
			||||||
	localizer := i18n.NewLocalizer(bundle, "en")
 | 
					 | 
				
			||||||
	catsMessage := &i18n.Message{
 | 
					 | 
				
			||||||
		ID:    "Cats",
 | 
					 | 
				
			||||||
		One:   "I have {{.PluralCount}} cat.",
 | 
					 | 
				
			||||||
		Other: "I have {{.PluralCount}} cats.",
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
					 | 
				
			||||||
		DefaultMessage: catsMessage,
 | 
					 | 
				
			||||||
		PluralCount:    1,
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
	fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
 | 
					 | 
				
			||||||
		DefaultMessage: catsMessage,
 | 
					 | 
				
			||||||
		PluralCount:    2,
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
 | 
						"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/naiba/nezha/model"
 | 
						"github.com/naiba/nezha/model"
 | 
				
			||||||
	"github.com/naiba/nezha/service/singleton"
 | 
						"github.com/naiba/nezha/service/singleton"
 | 
				
			||||||
@ -34,6 +35,15 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
 | 
				
			|||||||
	if ok {
 | 
						if ok {
 | 
				
			||||||
		data["Admin"] = u
 | 
							data["Admin"] = u
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						data["LANG"] = map[string]string{
 | 
				
			||||||
 | 
							"Add":          singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Add"}),
 | 
				
			||||||
 | 
							"Edit":         singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Edit"}),
 | 
				
			||||||
 | 
							"AlarmRule":    singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "AlarmRule"}),
 | 
				
			||||||
 | 
							"Notification": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NotificationMethod"}),
 | 
				
			||||||
 | 
							"Server":       singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Server"}),
 | 
				
			||||||
 | 
							"Monitor":      singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
 | 
				
			||||||
 | 
							"Cron":         singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return data
 | 
						return data
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -68,3 +68,14 @@ func IPDesensitize(ipAddr string) string {
 | 
				
			|||||||
	ipAddr = ipv6Desensitize(ipAddr)
 | 
						ipAddr = ipv6Desensitize(ipAddr)
 | 
				
			||||||
	return ipAddr
 | 
						return ipAddr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func PathExists(path string) (bool, error) {
 | 
				
			||||||
 | 
						_, err := os.Stat(path)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if os.IsNotExist(err) {
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,19 @@
 | 
				
			|||||||
 | 
					let LANG = {
 | 
				
			||||||
 | 
					  Add: "添加",
 | 
				
			||||||
 | 
					  Edit: "修改",
 | 
				
			||||||
 | 
					  AlarmRule: "报警规则",
 | 
				
			||||||
 | 
					  Notification: "通知方式",
 | 
				
			||||||
 | 
					  Server: "服务器",
 | 
				
			||||||
 | 
					  Monitor: "监控",
 | 
				
			||||||
 | 
					  Cron: "计划任务",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updateLang(newLang) {
 | 
				
			||||||
 | 
					  if (newLang) {
 | 
				
			||||||
 | 
					    LANG = newLang;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function readableBytes(bytes) {
 | 
					function readableBytes(bytes) {
 | 
				
			||||||
  if (!bytes) {
 | 
					  if (!bytes) {
 | 
				
			||||||
    return '0B'
 | 
					    return '0B'
 | 
				
			||||||
@ -105,11 +121,11 @@ function showFormModal(modelSelector, formID, URL, getData) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function addOrEditAlertRule(rule) {
 | 
					function addOrEditAlertRule(rule) {
 | 
				
			||||||
  const modal = $(".rule.modal");
 | 
					  const modal = $(".rule.modal");
 | 
				
			||||||
  modal.children(".header").text((rule ? "修改" : "添加") + "报警规则");
 | 
					  modal.children(".header").text((rule ? LANG.Edit : LANG.Add) + ' ' + LANG.AlarmRule);
 | 
				
			||||||
  modal
 | 
					  modal
 | 
				
			||||||
    .find(".nezha-primary-btn.button")
 | 
					    .find(".nezha-primary-btn.button")
 | 
				
			||||||
    .html(
 | 
					    .html(
 | 
				
			||||||
      rule ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
 | 
					      rule ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  modal.find("input[name=ID]").val(rule ? rule.ID : null);
 | 
					  modal.find("input[name=ID]").val(rule ? rule.ID : null);
 | 
				
			||||||
  modal.find("input[name=Name]").val(rule ? rule.Name : null);
 | 
					  modal.find("input[name=Name]").val(rule ? rule.Name : null);
 | 
				
			||||||
@ -125,13 +141,13 @@ function addOrEditAlertRule(rule) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function addOrEditNotification(notification) {
 | 
					function addOrEditNotification(notification) {
 | 
				
			||||||
  const modal = $(".notification.modal");
 | 
					  const modal = $(".notification.modal");
 | 
				
			||||||
  modal.children(".header").text((notification ? "修改" : "添加") + "通知方式");
 | 
					  modal.children(".header").text((notification ? LANG.Edit : LANG.Add) + ' ' + LANG.Notification);
 | 
				
			||||||
  modal
 | 
					  modal
 | 
				
			||||||
    .find(".nezha-primary-btn.button")
 | 
					    .find(".nezha-primary-btn.button")
 | 
				
			||||||
    .html(
 | 
					    .html(
 | 
				
			||||||
      notification
 | 
					      notification
 | 
				
			||||||
        ? '修改<i class="edit icon"></i>'
 | 
					        ? LANG.Edit + '<i class="edit icon"></i>'
 | 
				
			||||||
        : '添加<i class="add icon"></i>'
 | 
					        : LANG.Add + '<i class="add icon"></i>'
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  modal.find("input[name=ID]").val(notification ? notification.ID : null);
 | 
					  modal.find("input[name=ID]").val(notification ? notification.ID : null);
 | 
				
			||||||
  modal.find("input[name=Name]").val(notification ? notification.Name : null);
 | 
					  modal.find("input[name=Name]").val(notification ? notification.Name : null);
 | 
				
			||||||
@ -188,11 +204,11 @@ function post(path, params, method = 'post') {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function addOrEditServer(server, conf) {
 | 
					function addOrEditServer(server, conf) {
 | 
				
			||||||
  const modal = $(".server.modal");
 | 
					  const modal = $(".server.modal");
 | 
				
			||||||
  modal.children(".header").text((server ? "修改" : "添加") + "服务器");
 | 
					  modal.children(".header").text((server ? LANG.Edit : LANG.Add) + ' ' + LANG.Server);
 | 
				
			||||||
  modal
 | 
					  modal
 | 
				
			||||||
    .find(".nezha-primary-btn.button")
 | 
					    .find(".nezha-primary-btn.button")
 | 
				
			||||||
    .html(
 | 
					    .html(
 | 
				
			||||||
      server ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
 | 
					      server ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  modal.find("input[name=id]").val(server ? server.ID : null);
 | 
					  modal.find("input[name=id]").val(server ? server.ID : null);
 | 
				
			||||||
  modal.find("input[name=name]").val(server ? server.Name : null);
 | 
					  modal.find("input[name=name]").val(server ? server.Name : null);
 | 
				
			||||||
@ -216,11 +232,11 @@ function addOrEditServer(server, conf) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function addOrEditMonitor(monitor) {
 | 
					function addOrEditMonitor(monitor) {
 | 
				
			||||||
  const modal = $(".monitor.modal");
 | 
					  const modal = $(".monitor.modal");
 | 
				
			||||||
  modal.children(".header").text((monitor ? "修改" : "添加") + "监控");
 | 
					  modal.children(".header").text((monitor ? LANG.Edit : LANG.Add) + ' ' + LANG.Monitor);
 | 
				
			||||||
  modal
 | 
					  modal
 | 
				
			||||||
    .find(".nezha-primary-btn.button")
 | 
					    .find(".nezha-primary-btn.button")
 | 
				
			||||||
    .html(
 | 
					    .html(
 | 
				
			||||||
      monitor ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
 | 
					      monitor ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  modal.find("input[name=ID]").val(monitor ? monitor.ID : null);
 | 
					  modal.find("input[name=ID]").val(monitor ? monitor.ID : null);
 | 
				
			||||||
  modal.find("input[name=Name]").val(monitor ? monitor.Name : null);
 | 
					  modal.find("input[name=Name]").val(monitor ? monitor.Name : null);
 | 
				
			||||||
@ -257,11 +273,11 @@ function addOrEditMonitor(monitor) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function addOrEditCron(cron) {
 | 
					function addOrEditCron(cron) {
 | 
				
			||||||
  const modal = $(".cron.modal");
 | 
					  const modal = $(".cron.modal");
 | 
				
			||||||
  modal.children(".header").text((cron ? "修改" : "添加") + "计划任务");
 | 
					  modal.children(".header").text((cron ? LANG.Edit : LANG.Add) + ' ' + LANG.Cron);
 | 
				
			||||||
  modal
 | 
					  modal
 | 
				
			||||||
    .find(".nezha-primary-btn.button")
 | 
					    .find(".nezha-primary-btn.button")
 | 
				
			||||||
    .html(
 | 
					    .html(
 | 
				
			||||||
      cron ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
 | 
					      cron ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  modal.find("input[name=ID]").val(cron ? cron.ID : null);
 | 
					  modal.find("input[name=ID]").val(cron ? cron.ID : null);
 | 
				
			||||||
  modal.find("input[name=Name]").val(cron ? cron.Name : null);
 | 
					  modal.find("input[name=Name]").val(cron ? cron.Name : null);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								resource/template/common/footer.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								resource/template/common/footer.html
									
									
									
									
										vendored
									
									
								
							@ -1,15 +1,21 @@
 | 
				
			|||||||
{{define "common/footer"}}
 | 
					{{define "common/footer"}}
 | 
				
			||||||
<div class="ui inverted vertical footer segment">
 | 
					<div class="ui inverted vertical footer segment">
 | 
				
			||||||
    <div class="ui center aligned is-size-7 container">
 | 
					    <div class="ui center aligned is-size-7 container">
 | 
				
			||||||
        <b>© <a style="color: white;" href="/">{{.Conf.Site.Brand}}</a></b> | <small>Powered by <a href="https://github.com/naiba/nezha"
 | 
					        <b>© <a style="color: white;" href="/">{{.Conf.Site.Brand}}</a></b> | <small>Powered by <a
 | 
				
			||||||
                style="color: white;" target="_blank">{{tr "nezhaMonitor"}}</a> {{.Version}}</small>
 | 
					                href="https://github.com/naiba/nezha" style="color: white;" target="_blank">{{tr "NezhaMonitoring"}}</a>
 | 
				
			||||||
 | 
					            {{.Version}}</small>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.4.1/jquery.min.js"></script>
 | 
					<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.4.1/jquery.min.js"></script>
 | 
				
			||||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/semantic-ui/2.4.1/semantic.min.js"></script>
 | 
					<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/semantic-ui/2.4.1/semantic.min.js"></script>
 | 
				
			||||||
<script src="/static/semantic-ui-alerts.min.js"></script>
 | 
					<script src="/static/semantic-ui-alerts.min.js"></script>
 | 
				
			||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.12/vue.min.js"></script>
 | 
					<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.12/vue.min.js"></script>
 | 
				
			||||||
<script src="/static/main.js?v20220423"></script>
 | 
					<script src="/static/main.js?v20220430"></script>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					    (function () {
 | 
				
			||||||
 | 
					        updateLang({{.LANG }});
 | 
				
			||||||
 | 
					    })();
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								resource/template/common/menu.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								resource/template/common/menu.html
									
									
									
									
										vendored
									
									
								
							@ -1,9 +1,9 @@
 | 
				
			|||||||
{{define "common/menu"}}
 | 
					{{define "common/menu"}}
 | 
				
			||||||
<div class="ui large top fixed menu nb-menu">
 | 
					<div class="ui large top fixed menu nb-menu">
 | 
				
			||||||
    <div class="ui container">
 | 
					    <div class="ui container">
 | 
				
			||||||
        <div class="item">
 | 
					        <a class="item" href="/">
 | 
				
			||||||
            <img src="/static/logo.svg?v20210804">
 | 
					            <img src="/static/logo.svg?v20210804">
 | 
				
			||||||
        </div>
 | 
					        </a>
 | 
				
			||||||
        {{if .IsAdminPage}}
 | 
					        {{if .IsAdminPage}}
 | 
				
			||||||
        <a class='item{{if eq .MatchedPath "/server"}} active{{end}}' href="/server"><i class="server icon"></i>{{tr "Server"}}</a>
 | 
					        <a class='item{{if eq .MatchedPath "/server"}} active{{end}}' href="/server"><i class="server icon"></i>{{tr "Server"}}</a>
 | 
				
			||||||
        <a class='item{{if eq .MatchedPath "/monitor"}} active{{end}}' href="/monitor"><i class="rss icon"></i>{{tr "Services"}}</a>
 | 
					        <a class='item{{if eq .MatchedPath "/monitor"}} active{{end}}' href="/monitor"><i class="rss icon"></i>{{tr "Services"}}</a>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								resource/template/component/cron.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								resource/template/component/cron.html
									
									
									
									
										vendored
									
									
								
							@ -33,7 +33,7 @@
 | 
				
			|||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
                <label>{{tr "NotificationMethod"}}}</label>
 | 
					                <label>{{tr "NotificationMethodGroup"}}}</label>
 | 
				
			||||||
                <input type="text" name="NotificationTag" placeholder="default">
 | 
					                <input type="text" name="NotificationTag" placeholder="default">
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								resource/template/component/monitor.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								resource/template/component/monitor.html
									
									
									
									
										vendored
									
									
								
							@ -45,7 +45,7 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="field">
 | 
					      <div class="field">
 | 
				
			||||||
        <label>{{tr "NotificationMethod"}}</label>
 | 
					        <label>{{tr "NotificationMethodGroup"}}</label>
 | 
				
			||||||
        <input type="text" name="NotificationTag" placeholder="default" />
 | 
					        <input type="text" name="NotificationTag" placeholder="default" />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="field">
 | 
					      <div class="field">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								resource/template/component/rule.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								resource/template/component/rule.html
									
									
									
									
										vendored
									
									
								
							@ -13,7 +13,7 @@
 | 
				
			|||||||
                <textarea name="RulesRaw"></textarea>
 | 
					                <textarea name="RulesRaw"></textarea>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
                <label>{{tr "NotificationMethod"}}</label>
 | 
					                <label>{{tr "NotificationMethodGroup"}}</label>
 | 
				
			||||||
                <input type="text" name="NotificationTag" placeholder="default">
 | 
					                <input type="text" name="NotificationTag" placeholder="default">
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
                    <th>{{tr "Name"}}</th>
 | 
					                    <th>{{tr "Name"}}</th>
 | 
				
			||||||
                    <th>{{tr "Scheduler"}}</th>
 | 
					                    <th>{{tr "Scheduler"}}</th>
 | 
				
			||||||
                    <th>{{tr "Command"}}</th>
 | 
					                    <th>{{tr "Command"}}</th>
 | 
				
			||||||
                    <th>{{tr "NotificationMethod"}}</th>
 | 
					                    <th>{{tr "NotificationMethodGroup"}}</th>
 | 
				
			||||||
                    <th>{{tr "PushSuccessfully"}}</th>
 | 
					                    <th>{{tr "PushSuccessfully"}}</th>
 | 
				
			||||||
                    <th>{{tr "Coverage"}}</th>
 | 
					                    <th>{{tr "Coverage"}}</th>
 | 
				
			||||||
                    <th>{{tr "SpecificServers"}}</th>
 | 
					                    <th>{{tr "SpecificServers"}}</th>
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@
 | 
				
			|||||||
          <th>{{tr "SpecificServers"}}</th>
 | 
					          <th>{{tr "SpecificServers"}}</th>
 | 
				
			||||||
          <th>{{tr "Type"}}</th>
 | 
					          <th>{{tr "Type"}}</th>
 | 
				
			||||||
          <th>{{tr "Duration"}}</th>
 | 
					          <th>{{tr "Duration"}}</th>
 | 
				
			||||||
          <th>{{tr "NotificationMethod"}}</th>
 | 
					          <th>{{tr "NotificationMethodGroup"}}</th>
 | 
				
			||||||
          <th>{{tr "Notification"}}</th>
 | 
					          <th>{{tr "Notification"}}</th>
 | 
				
			||||||
          <th>{{tr "Administration"}}</th>
 | 
					          <th>{{tr "Administration"}}</th>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,7 @@
 | 
				
			|||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
                    <th>ID</th>
 | 
					                    <th>ID</th>
 | 
				
			||||||
                    <th>{{tr "Name"}}</th>
 | 
					                    <th>{{tr "Name"}}</th>
 | 
				
			||||||
                    <th>{{tr "NotificationMethod"}}</th>
 | 
					                    <th>{{tr "NotificationMethodGroup"}}</th>
 | 
				
			||||||
                    <th>{{tr "Rules"}}</th>
 | 
					                    <th>{{tr "Rules"}}</th>
 | 
				
			||||||
                    <th>{{tr "Enable"}}</th>
 | 
					                    <th>{{tr "Enable"}}</th>
 | 
				
			||||||
                    <th>{{tr "Administration"}}</th>
 | 
					                    <th>{{tr "Administration"}}</th>
 | 
				
			||||||
 | 
				
			|||||||
@ -44,15 +44,11 @@
 | 
				
			|||||||
                            data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
 | 
					                            data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
 | 
				
			||||||
                            <i class="linux icon"></i>
 | 
					                            <i class="linux icon"></i>
 | 
				
			||||||
                        </button>
 | 
					                        </button>
 | 
				
			||||||
                        <button class="ui icon mini button" data-tooltip="{{tr "NotSupportedYet"}}">
 | 
					 | 
				
			||||||
                        <button class="ui icon green mini button"
 | 
					                        <button class="ui icon green mini button"
 | 
				
			||||||
                            data-clipboard-text="{{if $.Conf.GRPCHost}}set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/naiba/nezha/master/script/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1 {{$.Conf.GRPCHost}}:{{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
 | 
					                            data-clipboard-text="{{if $.Conf.GRPCHost}}set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/naiba/nezha/master/script/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1 {{$.Conf.GRPCHost}}:{{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
 | 
				
			||||||
                            data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
 | 
					                            data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
 | 
				
			||||||
                            <i class="windows icon"></i>
 | 
					                            <i class="windows icon"></i>
 | 
				
			||||||
                        </button>
 | 
					                        </button>
 | 
				
			||||||
                        <button class="ui icon mini button" data-tooltip="{{tr "NotSupportedYet"}}">
 | 
					 | 
				
			||||||
                            <i class="apple icon"></i>
 | 
					 | 
				
			||||||
                        </button>
 | 
					 | 
				
			||||||
                    </td>
 | 
					                    </td>
 | 
				
			||||||
                    <td style="word-break: break-word;">{{$server.Note}}</td>
 | 
					                    <td style="word-break: break-word;">{{$server.Note}}</td>
 | 
				
			||||||
                    <td>
 | 
					                    <td>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
        <form id="settingForm" class="ui large form" onsubmit="return false;">
 | 
					        <form id="settingForm" class="ui large form" onsubmit="return false;">
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
                <label>{{tr "SiteTitle"}}</label>
 | 
					                <label>{{tr "SiteTitle"}}</label>
 | 
				
			||||||
                <input type="text" name="Title" placeholder="{{tr "nezhaMonitor"}}" value="{{.Conf.Site.Brand}}">
 | 
					                <input type="text" name="Title" placeholder="{{tr "NezhaMonitoring"}}" value="{{.Conf.Site.Brand}}">
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
                <label>{{tr "AdministratorList"}}</label>
 | 
					                <label>{{tr "AdministratorList"}}</label>
 | 
				
			||||||
@ -24,12 +24,21 @@
 | 
				
			|||||||
                    <option value="mdui" {{if eq .Conf.Site.Theme "mdui" }} selected="selected" {{end}}>Neko Mdui</option>
 | 
					                    <option value="mdui" {{if eq .Conf.Site.Theme "mdui" }} selected="selected" {{end}}>Neko Mdui</option>
 | 
				
			||||||
                </select>
 | 
					                </select>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					                <label>Language</label>
 | 
				
			||||||
 | 
					                <select name="Language">
 | 
				
			||||||
 | 
					                    <option value="zh-CN" {{if eq .Conf.Language "zh-CN" }} selected="selected" {{end}}>
 | 
				
			||||||
 | 
					                        简体中文</option>
 | 
				
			||||||
 | 
					                    <option value="en-US" {{if eq .Conf.Language "en-US" }} selected="selected" {{end}}>
 | 
				
			||||||
 | 
					                        English</option>
 | 
				
			||||||
 | 
					                </select>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
                <label>{{tr "CustomCodes"}}</label>
 | 
					                <label>{{tr "CustomCodes"}}</label>
 | 
				
			||||||
                <textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
 | 
					                <textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
                <label>{{tr "AccessPassword"}}}</label>
 | 
					                <label>{{tr "AccessPassword"}}</label>
 | 
				
			||||||
                <input type="text" name="ViewPassword" placeholder="" value="{{.Conf.Site.ViewPassword}}">
 | 
					                <input type="text" name="ViewPassword" placeholder="" value="{{.Conf.Site.ViewPassword}}">
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="field">
 | 
					            <div class="field">
 | 
				
			||||||
@ -86,6 +95,7 @@
 | 
				
			|||||||
                        time: '3',
 | 
					                        time: '3',
 | 
				
			||||||
                        position: 'top-center',
 | 
					                        position: 'top-center',
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
 | 
					                    window.location.reload()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    $.suiAlert({
 | 
					                    $.suiAlert({
 | 
				
			||||||
                        title: '',
 | 
					                        title: '',
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								resource/template/theme-daynight/home.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								resource/template/theme-daynight/home.html
									
									
									
									
										vendored
									
									
								
							@ -23,7 +23,7 @@
 | 
				
			|||||||
        <section class="nav-bar clearfix">
 | 
					        <section class="nav-bar clearfix">
 | 
				
			||||||
            <figure class="logo">
 | 
					            <figure class="logo">
 | 
				
			||||||
                <a href="/">
 | 
					                <a href="/">
 | 
				
			||||||
                    <img src="/static/logo.svg?v20210804" alt='{{tr "nezhaMonitor"}}' width="50" height="50">
 | 
					                    <img src="/static/logo.svg?v20210804" alt='{{tr "NezhaMonitoring"}}' width="50" height="50">
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
                <a href="/">{{.Conf.Site.Brand}}</a>
 | 
					                <a href="/">{{.Conf.Site.Brand}}</a>
 | 
				
			||||||
            </figure>
 | 
					            </figure>
 | 
				
			||||||
@ -155,7 +155,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <footer>
 | 
					    <footer>
 | 
				
			||||||
        <div class="footer-container">
 | 
					        <div class="footer-container">
 | 
				
			||||||
            <div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor"}} · {{.Version}}</a>
 | 
					            <div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
 | 
				
			||||||
                <p>© <span id="copyright-date">
 | 
					                <p>© <span id="copyright-date">
 | 
				
			||||||
                        <script>document.getElementById('copyright-date').appendChild(document.createTextNode(new Date().getFullYear()))</script>
 | 
					                        <script>document.getElementById('copyright-date').appendChild(document.createTextNode(new Date().getFullYear()))</script>
 | 
				
			||||||
                    </span> · <a href="https://blog.jackiesung.com" target="_blank">Theme designed by Jackie Sung</a>
 | 
					                    </span> · <a href="https://blog.jackiesung.com" target="_blank">Theme designed by Jackie Sung</a>
 | 
				
			||||||
 | 
				
			|||||||
@ -118,7 +118,7 @@
 | 
				
			|||||||
      <footer>
 | 
					      <footer>
 | 
				
			||||||
        <div class="footer-container">
 | 
					        <div class="footer-container">
 | 
				
			||||||
          <div>
 | 
					          <div>
 | 
				
			||||||
            <a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor"}} · {{.Version}}</a>
 | 
					            <a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
 | 
				
			||||||
            <p>
 | 
					            <p>
 | 
				
			||||||
              ©
 | 
					              ©
 | 
				
			||||||
              <span id="copyright-date"
 | 
					              <span id="copyright-date"
 | 
				
			||||||
 | 
				
			|||||||
@ -42,7 +42,7 @@
 | 
				
			|||||||
    <footer>
 | 
					    <footer>
 | 
				
			||||||
      <div class="footer-container">
 | 
					      <div class="footer-container">
 | 
				
			||||||
        <div>
 | 
					        <div>
 | 
				
			||||||
          <a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor"}} · {{.Version}}</a>
 | 
					          <a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
 | 
				
			||||||
          <p>
 | 
					          <p>
 | 
				
			||||||
            ©<span id="copyright-date"
 | 
					            ©<span id="copyright-date"
 | 
				
			||||||
              ><script>
 | 
					              ><script>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								resource/template/theme-hotaru/home.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								resource/template/theme-hotaru/home.html
									
									
									
									
										vendored
									
									
								
							@ -135,7 +135,7 @@
 | 
				
			|||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <footer>
 | 
					    <footer>
 | 
				
			||||||
        <p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">{{tr "nezhaMonitor"}}</a> build ·
 | 
					        <p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">{{tr "NezhaMonitoring"}}</a> build ·
 | 
				
			||||||
            {{.Version}}
 | 
					            {{.Version}}
 | 
				
			||||||
            <a href="/service">{{tr "Services"}}</a>
 | 
					            <a href="/service">{{tr "Services"}}</a>
 | 
				
			||||||
            <a href="/server">{{tr "AdminPanel"}}</a>
 | 
					            <a href="/server">{{tr "AdminPanel"}}</a>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								resource/template/theme-mdui/footer.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								resource/template/theme-mdui/footer.html
									
									
									
									
										vendored
									
									
								
							@ -5,7 +5,7 @@
 | 
				
			|||||||
    <center>
 | 
					    <center>
 | 
				
			||||||
      <p>
 | 
					      <p>
 | 
				
			||||||
        <a href="/"><at>{{.Title}}</at></a>
 | 
					        <a href="/"><at>{{.Title}}</at></a>
 | 
				
			||||||
        Powered by <a href="https://github.com/naiba/nezha"><st>{{tr "nezhaMonitor"}}<{{.Version}}></st></a> | Theme designed by Mikoy Chinese
 | 
					        Powered by <a href="https://github.com/naiba/nezha"><st>{{tr "NezhaMonitoring"}}<{{.Version}}></st></a> | Theme designed by Mikoy Chinese
 | 
				
			||||||
      </p>
 | 
					      </p>
 | 
				
			||||||
    </center>
 | 
					    </center>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
debug: false
 | 
					debug: false
 | 
				
			||||||
httpport: 80
 | 
					httpport: 80
 | 
				
			||||||
 | 
					language: nz_language
 | 
				
			||||||
grpcport: nz_grpc_port
 | 
					grpcport: nz_grpc_port
 | 
				
			||||||
oauth2:
 | 
					oauth2:
 | 
				
			||||||
  type: "nz_oauth2_type" #Oauth2 登录接入类型,gitee/github
 | 
					  type: "nz_oauth2_type" #Oauth2 登录接入类型,gitee/github
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,7 @@ NZ_BASE_PATH="/opt/nezha"
 | 
				
			|||||||
NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
 | 
					NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
 | 
				
			||||||
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
 | 
					NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
 | 
				
			||||||
NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service"
 | 
					NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service"
 | 
				
			||||||
NZ_VERSION="v0.9.0"
 | 
					NZ_VERSION="v0.9.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
red='\033[0;31m'
 | 
					red='\033[0;31m'
 | 
				
			||||||
green='\033[0;32m'
 | 
					green='\033[0;32m'
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,7 @@ NZ_BASE_PATH="/opt/nezha"
 | 
				
			|||||||
NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
 | 
					NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
 | 
				
			||||||
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
 | 
					NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
 | 
				
			||||||
NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service"
 | 
					NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service"
 | 
				
			||||||
NZ_VERSION="v0.9.0"
 | 
					NZ_VERSION="v0.9.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
red='\033[0;31m'
 | 
					red='\033[0;31m'
 | 
				
			||||||
green='\033[0;32m'
 | 
					green='\033[0;32m'
 | 
				
			||||||
@ -290,10 +290,12 @@ modify_dashboard_config() {
 | 
				
			|||||||
    sed -i "s/nz_github_oauth_client_id/${nz_github_oauth_client_id}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
					    sed -i "s/nz_github_oauth_client_id/${nz_github_oauth_client_id}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
				
			||||||
    sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
					    sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
				
			||||||
    sed -i "s/nz_site_title/${nz_site_title}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
					    sed -i "s/nz_site_title/${nz_site_title}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
				
			||||||
 | 
					    sed -i "s/nz_language/en-US/" ${NZ_DASHBOARD_PATH}/data/config.yaml
 | 
				
			||||||
    sed -i "s/nz_site_port/${nz_site_port}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
 | 
					    sed -i "s/nz_site_port/${nz_site_port}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
 | 
				
			||||||
    sed -i "s/nz_grpc_port/${nz_grpc_port}/g" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
 | 
					    sed -i "s/nz_grpc_port/${nz_grpc_port}/g" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
 | 
				
			||||||
    sed -i "s/nz_image_url/${Docker_IMG}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
 | 
					    sed -i "s/nz_image_url/${Docker_IMG}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    echo -e "Dashboard configuration ${green} modified successfully, please wait for Dashboard self-restart to take effect${plain}"
 | 
					    echo -e "Dashboard configuration ${green} modified successfully, please wait for Dashboard self-restart to take effect${plain}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    restart_and_update
 | 
					    restart_and_update
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,10 @@
 | 
				
			|||||||
package singleton
 | 
					package singleton
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/BurntSushi/toml"
 | 
						"github.com/BurntSushi/toml"
 | 
				
			||||||
 | 
						"github.com/naiba/nezha/pkg/utils"
 | 
				
			||||||
	"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
						"github.com/nicksnyder/go-i18n/v2/i18n"
 | 
				
			||||||
	"golang.org/x/text/language"
 | 
						"golang.org/x/text/language"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -11,12 +14,20 @@ var Localizer *i18n.Localizer
 | 
				
			|||||||
func InitLocalizer() {
 | 
					func InitLocalizer() {
 | 
				
			||||||
	bundle := i18n.NewBundle(language.Chinese)
 | 
						bundle := i18n.NewBundle(language.Chinese)
 | 
				
			||||||
	bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
 | 
						bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
 | 
				
			||||||
	_, err := bundle.LoadMessageFile("resource/l10n/" + Conf.Language + ".toml")
 | 
					
 | 
				
			||||||
 | 
						userCustomLanguageFile := "resource/l10n/" + Conf.Language + ".toml"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if exists, err := utils.PathExists(userCustomLanguageFile); !exists {
 | 
				
			||||||
 | 
							log.Println("NEZHA>> language file not found:", userCustomLanguageFile, err)
 | 
				
			||||||
 | 
							Conf.Language = "zh-CN"
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							_, err := bundle.LoadMessageFile(userCustomLanguageFile)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			panic(err)
 | 
								panic(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	_, err = bundle.LoadMessageFile("resource/l10n/zh-CN.toml")
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
					
 | 
				
			||||||
 | 
						if _, err := bundle.LoadMessageFile("resource/l10n/zh-CN.toml"); err != nil {
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	Localizer = i18n.NewLocalizer(bundle, Conf.Language)
 | 
						Localizer = i18n.NewLocalizer(bundle, Conf.Language)
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ import (
 | 
				
			|||||||
	"github.com/naiba/nezha/pkg/utils"
 | 
						"github.com/naiba/nezha/pkg/utils"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Version = "v0.12.30" // !!记得修改 README 中的 badge 版本!!
 | 
					var Version = "v0.13.1" // !!记得修改 README 中的 badge 版本!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	Conf  *model.Config
 | 
						Conf  *model.Config
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user