diff --git a/README.md b/README.md index d540458..0fa2a1c 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ RCON. Without it the panel still works, but shows the server as offline and can' | See IP addresses | `@css/showip` | | Change map | `@css/changemap` | | Server cvars | `@css/cvar` | + | See the Staff & ranks page | `@zio/webpanel` | | Ranks, staff, SimpleAdmin settings, reload admins | `@css/root` | `@css/root` grants everything. Nobody can act on a player whose immunity is higher than theirs, diff --git a/internal/web/admin.go b/internal/web/admin.go index 8556cb6..d8f99af 100644 --- a/internal/web/admin.go +++ b/internal/web/admin.go @@ -285,6 +285,7 @@ var knownFlags = [][3]string{ {"@css/vip", "VIP", "VIP perks in other plugins"}, // Our own flags: admin_overrides.json (in the server repo) moves these commands onto them, and // our SimpleAdmin fork checks @zio/penalties itself. Each command also accepts @css/root. + // @zio/webpanel is the panel's own: it shows the Staff & ranks page (adminStaff). {"@zio/menu", "Admin menu", "css_admin and css_adminhelp"}, {"@zio/who", "Who", "css_who and css_players"}, {"@zio/penalties", "Others' penalties", "css_penalties on another player"}, @@ -297,10 +298,15 @@ var knownFlags = [][3]string{ {"@zio/restart", "Restart game", "css_rr, css_rg, css_restart and css_restartgame"}, {"@zio/vote", "Start votes", "css_vote"}, {"@zio/plugins", "Plugins", "css_plugins and css"}, + {"@zio/webpanel", "Staff page", "See the Staff & ranks page in this panel"}, {"@css/root", "Root", "Every permission, and managing ranks and staff"}, } func (s *Server) adminStaff(w http.ResponseWriter, r *http.Request, id *Identity, x *staffIndex) { + if !id.Has("@zio/webpanel") { + fail(w, http.StatusForbidden, "You need @zio/webpanel to see the staff page.") + return + } st := s.poll.Current() groups := s.groupViews(x, st, true) diff --git a/internal/web/assets/admin.js b/internal/web/assets/admin.js index 320a3f8..24b98b2 100644 --- a/internal/web/assets/admin.js +++ b/internal/web/assets/admin.js @@ -6,7 +6,7 @@ const PAGES = [ { id: "players", label: "Players" }, { id: "bans", label: "Bans" }, { id: "comms", label: "Gags & mutes" }, - { id: "staff", label: "Staff & ranks" }, + { id: "staff", label: "Staff & ranks", flag: "@zio/webpanel" }, { id: "settings", label: "Server settings" }, ]; @@ -645,7 +645,7 @@ const RENDER = { overview, players, bans, comms, staff, settings }; function renderNav() { const c = state.counts; const count = { players: c.players, bans: c.bans, comms: c.comms, staff: c.staff }; - $("#nav-links").innerHTML = PAGES.map((p) => `
  • ${p.label}${count[p.id] !== undefined && count[p.id] !== "" ? `${esc(count[p.id])}` : ""}
  • `).join(""); + $("#nav-links").innerHTML = PAGES.filter((p) => !p.flag || can(p.flag)).map((p) => `
  • ${p.label}${count[p.id] !== undefined && count[p.id] !== "" ? `${esc(count[p.id])}` : ""}
  • `).join(""); } // The mobile sidebar covers the Menu button, so it closes from its own Close button, the @@ -657,7 +657,8 @@ function setNav(open) { function route() { const page = location.hash.slice(1); - state.page = RENDER[page] ? page : "overview"; + const def = PAGES.find((p) => p.id === page); + state.page = def && (!def.flag || can(def.flag)) ? page : "overview"; renderNav(); setNav(false); if (!$("#view").innerHTML) $("#view").innerHTML = loading();