🚀 dashboard v0.14.4 hide the server from guests

This commit is contained in:
naiba 2022-09-30 22:40:56 +08:00
parent ad4c0a15ab
commit d1f3c47cee
11 changed files with 65 additions and 14 deletions

View File

@ -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.14.3&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.10.7-brightgreen?style=for-the-badge&logo=linux"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.14.4&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.10.7-brightgreen?style=for-the-badge&logo=linux">
<br> <br>
<br> <br>
<p>:trollface: <b>Nezha Monitoring: Self-hosted, lightweight server and website monitoring and O&M tool.</b></p> <p>:trollface: <b>Nezha Monitoring: Self-hosted, lightweight server and website monitoring and O&M tool.</b></p>

View File

@ -101,6 +101,7 @@ func (p *commonPage) checkViewPassword(c *gin.Context) {
return return
} }
c.Set(model.CtxKeyViewPasswordVerified, true)
c.Next() c.Next()
} }
@ -125,20 +126,32 @@ func (p *commonPage) service(c *gin.Context) {
})) }))
} }
func (cp *commonPage) getServerStat() ([]byte, error) { func (cp *commonPage) getServerStat(c *gin.Context) ([]byte, error) {
v, err, _ := cp.requestGroup.Do("serverStats", func() (any, error) { v, err, _ := cp.requestGroup.Do("serverStats", func() (any, error) {
singleton.SortedServerLock.RLock() singleton.SortedServerLock.RLock()
defer singleton.SortedServerLock.RUnlock() defer singleton.SortedServerLock.RUnlock()
_, isMember := c.Get(model.CtxKeyAuthorizedUser)
_, isViewPasswordVerfied := c.Get(model.CtxKeyViewPasswordVerified)
var servers []*model.Server
if isMember || isViewPasswordVerfied {
servers = singleton.SortedServerList
} else {
servers = singleton.SortedServerListForGuest
}
return utils.Json.Marshal(Data{ return utils.Json.Marshal(Data{
Now: time.Now().Unix() * 1000, Now: time.Now().Unix() * 1000,
Servers: singleton.SortedServerList, Servers: servers,
}) })
}) })
return v.([]byte), err return v.([]byte), err
} }
func (cp *commonPage) home(c *gin.Context) { func (cp *commonPage) home(c *gin.Context) {
stat, err := cp.getServerStat() stat, err := cp.getServerStat(c)
if err != nil { if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{ mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
@ -186,7 +199,7 @@ func (cp *commonPage) ws(c *gin.Context) {
defer conn.Close() defer conn.Close()
count := 0 count := 0
for { for {
stat, err := cp.getServerStat() stat, err := cp.getServerStat(c)
if err != nil { if err != nil {
continue continue
} }

View File

@ -306,6 +306,7 @@ type serverForm struct {
Secret string Secret string
Tag string Tag string
Note string Note string
HideForGuest string
} }
func (ma *memberAPI) addOrEditServer(c *gin.Context) { func (ma *memberAPI) addOrEditServer(c *gin.Context) {
@ -321,6 +322,7 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
s.ID = sf.ID s.ID = sf.ID
s.Tag = sf.Tag s.Tag = sf.Tag
s.Note = sf.Note s.Note = sf.Note
s.HideForGuest = sf.HideForGuest == "on"
if s.ID == 0 { if s.ID == 0 {
s.Secret = utils.MD5(fmt.Sprintf("%s%s%d", time.Now(), sf.Name, admin.ID)) s.Secret = utils.MD5(fmt.Sprintf("%s%s%d", time.Now(), sf.Name, admin.ID))
s.Secret = s.Secret[:18] s.Secret = s.Secret[:18]

View File

@ -5,7 +5,7 @@ import (
) )
const CtxKeyAuthorizedUser = "ckau" const CtxKeyAuthorizedUser = "ckau"
const CtxKeyViewPasswordVerified = "ckvpv"
const CacheKeyOauth2State = "p:a:state" const CacheKeyOauth2State = "p:a:state"
type Common struct { type Common struct {

View File

@ -16,6 +16,7 @@ type Server struct {
Secret string `gorm:"uniqueIndex" json:"-"` Secret string `gorm:"uniqueIndex" json:"-"`
Note string `json:"-"` // 管理员可见备注 Note string `json:"-"` // 管理员可见备注
DisplayIndex int // 展示排序,越大越靠前 DisplayIndex int // 展示排序,越大越靠前
HideForGuest bool // 对游客隐藏
Host *Host `gorm:"-"` Host *Host `gorm:"-"`
State *HostState `gorm:"-"` State *HostState `gorm:"-"`
@ -38,10 +39,17 @@ func (s *Server) CopyFromRunningServer(old *Server) {
s.PrevHourlyTransferOut = old.PrevHourlyTransferOut s.PrevHourlyTransferOut = old.PrevHourlyTransferOut
} }
func boolToString(b bool) string {
if b {
return "true"
}
return "false"
}
func (s Server) Marshal() template.JS { func (s Server) Marshal() template.JS {
name, _ := utils.Json.Marshal(s.Name) name, _ := utils.Json.Marshal(s.Name)
tag, _ := utils.Json.Marshal(s.Tag) tag, _ := utils.Json.Marshal(s.Tag)
note, _ := utils.Json.Marshal(s.Note) note, _ := utils.Json.Marshal(s.Note)
secret, _ := utils.Json.Marshal(s.Secret) secret, _ := utils.Json.Marshal(s.Secret)
return template.JS(fmt.Sprintf(`{"ID":%d,"Name":%s,"Secret":%s,"DisplayIndex":%d,"Tag":%s,"Note":%s}`, s.ID, name, secret, s.DisplayIndex, tag, note)) // #nosec return template.JS(fmt.Sprintf(`{"ID":%d,"Name":%s,"Secret":%s,"DisplayIndex":%d,"Tag":%s,"Note":%s,"HideForGuest": %s}`, s.ID, name, secret, s.DisplayIndex, tag, note, boolToString(s.HideForGuest))) // #nosec
} }

View File

@ -292,6 +292,11 @@ function addOrEditServer(server, conf) {
modal.find(".command.field").attr("style", "display:none"); modal.find(".command.field").attr("style", "display:none");
modal.find("input[name=secret]").val(""); modal.find("input[name=secret]").val("");
} }
if (server && server.HideForGuest) {
modal.find(".ui.hideforguest.checkbox").checkbox("set checked");
} else {
modal.find(".ui.hideforguest.checkbox").checkbox("set unchecked");
}
showFormModal(".server.modal", "#serverForm", "/api/server"); showFormModal(".server.modal", "#serverForm", "/api/server");
} }

View File

@ -10,7 +10,7 @@
<script src="https://cdn.staticfile.org/semantic-ui/2.4.1/semantic.min.js"></script> <script src="https://cdn.staticfile.org/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://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script> <script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<script src="/static/main.js?v20220917"></script> <script src="/static/main.js?v20220930"></script>
<script> <script>
(function () { (function () {
updateLang({{.LANG }}); updateLang({{.LANG }});

View File

@ -20,11 +20,16 @@
<label>{{tr "Secret"}}</label> <label>{{tr "Secret"}}</label>
<input type="text" name="secret"> <input type="text" name="secret">
</div> </div>
<div class="field">
<div class="ui hideforguest checkbox">
<input name="HideForGuest" type="checkbox" tabindex="0" class="hidden" />
<label>{{tr "HideForGuest"}}</label>
</div>
</div>
<div class="field"> <div class="field">
<label>{{tr "Note"}}</label> <label>{{tr "Note"}}</label>
<textarea name="Note"></textarea> <textarea name="Note"></textarea>
</div> </div>
<div class="command field"> <div class="command field">
<label>{{tr "LinuxOneKeyInstall"}}</label> <label>{{tr "LinuxOneKeyInstall"}}</label>
<div class="ui message"> <div class="ui message">

View File

@ -25,6 +25,7 @@
<th>{{tr "ServerGroup"}}</th> <th>{{tr "ServerGroup"}}</th>
<th>IP</th> <th>IP</th>
<th>{{tr "VersionNumber"}}</th> <th>{{tr "VersionNumber"}}</th>
<th>{{tr "HideForGuest"}}</th>
<th>{{tr "Secret"}}</th> <th>{{tr "Secret"}}</th>
<th>{{tr "OneKeyInstall"}}</th> <th>{{tr "OneKeyInstall"}}</th>
<th>{{tr "Note"}}</th> <th>{{tr "Note"}}</th>
@ -40,7 +41,12 @@
<td>{{$server.Tag}}</td> <td>{{$server.Tag}}</td>
<td>{{$server.Host.IP}}</td> <td>{{$server.Host.IP}}</td>
<td>{{$server.Host.Version}}</td> <td>{{$server.Host.Version}}</td>
<td>{{$server.Secret}}</td> <td>{{$server.HideForGuest}}</td>
<td>
<button class="ui icon green mini button" data-clipboard-text="{{$server.Secret}}">
<i class="copy icon"></i>
</button>
</td>
<td> <td>
<button class="ui icon green mini button" <button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}{{if eq $.Conf.Language "zh-CN"}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh{{else}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install_en.sh{{end}} -o nezha.sh && chmod +x nezha.sh && sudo ./nezha.sh install_agent {{$.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}}{{if eq $.Conf.Language "zh-CN"}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh{{else}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install_en.sh{{end}} -o nezha.sh && chmod +x nezha.sh && sudo ./nezha.sh install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"

View File

@ -13,8 +13,9 @@ var (
ServerTagToIDList map[string][]uint64 // [ServerTag] -> ServerID ServerTagToIDList map[string][]uint64 // [ServerTag] -> ServerID
ServerLock sync.RWMutex ServerLock sync.RWMutex
SortedServerList []*model.Server // 用于存储服务器列表的 slice按照服务器 ID 排序 SortedServerList []*model.Server // 用于存储服务器列表的 slice按照服务器 ID 排序
SortedServerLock sync.RWMutex SortedServerListForGuest []*model.Server
SortedServerLock sync.RWMutex
) )
// InitServer 初始化 ServerID <-> Secret 的映射 // InitServer 初始化 ServerID <-> Secret 的映射
@ -24,7 +25,7 @@ func InitServer() {
ServerTagToIDList = make(map[string][]uint64) ServerTagToIDList = make(map[string][]uint64)
} }
//LoadServers 加载服务器列表并根据ID排序 // LoadServers 加载服务器列表并根据ID排序
func LoadServers() { func LoadServers() {
InitServer() InitServer()
var servers []model.Server var servers []model.Server
@ -48,8 +49,12 @@ func ReSortServer() {
defer SortedServerLock.Unlock() defer SortedServerLock.Unlock()
SortedServerList = []*model.Server{} SortedServerList = []*model.Server{}
SortedServerListForGuest = []*model.Server{}
for _, s := range ServerList { for _, s := range ServerList {
SortedServerList = append(SortedServerList, s) SortedServerList = append(SortedServerList, s)
if !s.HideForGuest {
SortedServerListForGuest = append(SortedServerListForGuest, s)
}
} }
// 按照服务器 ID 排序的具体实现ID越大越靠前 // 按照服务器 ID 排序的具体实现ID越大越靠前
@ -59,4 +64,11 @@ func ReSortServer() {
} }
return SortedServerList[i].DisplayIndex > SortedServerList[j].DisplayIndex return SortedServerList[i].DisplayIndex > SortedServerList[j].DisplayIndex
}) })
sort.SliceStable(SortedServerListForGuest, func(i, j int) bool {
if SortedServerListForGuest[i].DisplayIndex == SortedServerListForGuest[j].DisplayIndex {
return SortedServerListForGuest[i].ID < SortedServerListForGuest[j].ID
}
return SortedServerListForGuest[i].DisplayIndex > SortedServerListForGuest[j].DisplayIndex
})
} }

View File

@ -12,7 +12,7 @@ import (
"github.com/naiba/nezha/pkg/utils" "github.com/naiba/nezha/pkg/utils"
) )
var Version = "v0.14.3" // !!记得修改 README 中的 badge 版本!! var Version = "v0.14.4" // !!记得修改 README 中的 badge 版本!!
var ( var (
Conf *model.Config Conf *model.Config