Merge pull request #137 from ssb-ngi-pointer/move-privacy-modes
Move privacy modes into proper settings view
This commit is contained in:
commit
f9652c6423
|
@ -3,18 +3,12 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
// "errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go.mindeco.de/http/render"
|
||||
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
// weberrors "github.com/ssb-ngi-pointer/go-ssb-room/web/errors"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomstate"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/router"
|
||||
)
|
||||
|
||||
type dashboardHandler struct {
|
||||
|
@ -38,50 +32,12 @@ func (h dashboardHandler) overview(w http.ResponseWriter, req *http.Request) (in
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to count denied keys: %w", err)
|
||||
}
|
||||
privacyModes := []roomdb.PrivacyMode{roomdb.ModeOpen, roomdb.ModeCommunity, roomdb.ModeRestricted}
|
||||
currentMode, err := h.dbs.Config.GetPrivacyMode(req.Context())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve current privacy mode: %w", err)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"OnlineRefs": onlineRefs,
|
||||
"OnlineCount": onlineCount,
|
||||
"MemberCount": memberCount,
|
||||
"InviteCount": inviteCount,
|
||||
"DeniedCount": deniedCount,
|
||||
"CurrentMode": currentMode,
|
||||
"PrivacyModes": privacyModes,
|
||||
csrf.TemplateTag: csrf.TemplateField(req),
|
||||
"OnlineRefs": onlineRefs,
|
||||
"OnlineCount": onlineCount,
|
||||
"MemberCount": memberCount,
|
||||
"InviteCount": inviteCount,
|
||||
"DeniedCount": deniedCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h dashboardHandler) setPrivacy(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "POST" {
|
||||
// TODO: proper error type
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("bad request"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
// TODO: proper error type
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("bad request: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
pmValue := req.Form.Get("privacy_mode")
|
||||
|
||||
pm := roomdb.ParsePrivacyMode(pmValue)
|
||||
if pm == roomdb.ModeUnknown {
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("unknown privacy mode was being set: %v", pmValue))
|
||||
}
|
||||
|
||||
err := h.dbs.Config.SetPrivacyMode(req.Context(), pm)
|
||||
if err != nil {
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("something went wrong when setting the privacy mode: %w", err))
|
||||
}
|
||||
|
||||
urlTo := web.NewURLTo(router.CompleteApp())
|
||||
dashboard := urlTo(router.AdminDashboard).String()
|
||||
http.Redirect(w, req, dashboard, http.StatusFound)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ var HTMLTemplates = []string{
|
|||
"admin/dashboard.tmpl",
|
||||
"admin/menu.tmpl",
|
||||
|
||||
"admin/settings.tmpl",
|
||||
|
||||
"admin/aliases-revoke-confirm.tmpl",
|
||||
|
||||
"admin/denied-keys.tmpl",
|
||||
|
@ -68,9 +70,14 @@ func Handler(
|
|||
dbs: dbs,
|
||||
roomState: roomState,
|
||||
}
|
||||
|
||||
mux.HandleFunc("/dashboard", r.HTML("admin/dashboard.tmpl", dashboardHandler.overview))
|
||||
mux.HandleFunc("/dashboard/set-privacy", dashboardHandler.setPrivacy)
|
||||
|
||||
var sh = settingsHandler{
|
||||
r: r,
|
||||
db: dbs.Config,
|
||||
}
|
||||
mux.HandleFunc("/settings", r.HTML("admin/settings.tmpl", sh.overview))
|
||||
mux.HandleFunc("/settings/set-privacy", sh.setPrivacy)
|
||||
|
||||
mux.HandleFunc("/menu", r.HTML("admin/menu.tmpl", func(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
return map[string]interface{}{}, nil
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
// "errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go.mindeco.de/http/render"
|
||||
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web"
|
||||
weberrors "github.com/ssb-ngi-pointer/go-ssb-room/web/errors"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/members"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/router"
|
||||
)
|
||||
|
||||
type settingsHandler struct {
|
||||
r *render.Renderer
|
||||
db roomdb.RoomConfig
|
||||
}
|
||||
|
||||
func (h settingsHandler) overview(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
privacyModes := []roomdb.PrivacyMode{roomdb.ModeOpen, roomdb.ModeCommunity, roomdb.ModeRestricted}
|
||||
currentMode, err := h.db.GetPrivacyMode(req.Context())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve current privacy mode: %w", err)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"CurrentMode": currentMode,
|
||||
"PrivacyModes": privacyModes,
|
||||
csrf.TemplateTag: csrf.TemplateField(req),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h settingsHandler) setPrivacy(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "POST" {
|
||||
// TODO: proper error type
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("bad request"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
// TODO: proper error type
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("bad request: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
// get the member behind the POST
|
||||
currentMember := members.FromContext(req.Context())
|
||||
if currentMember == nil {
|
||||
err := weberrors.ErrForbidden{Details: fmt.Errorf("not a registered member")}
|
||||
h.r.Error(w, req, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
// make sure the member is an admin
|
||||
if currentMember.Role != roomdb.RoleAdmin {
|
||||
err := weberrors.ErrForbidden{Details: fmt.Errorf("yr not an admin! naughty naughty")}
|
||||
h.r.Error(w, req, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
pmValue := req.Form.Get("privacy_mode")
|
||||
pm := roomdb.ParsePrivacyMode(pmValue)
|
||||
if pm == roomdb.ModeUnknown {
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("unknown privacy mode was being set: %v", pmValue))
|
||||
}
|
||||
|
||||
err := h.db.SetPrivacyMode(req.Context(), pm)
|
||||
if err != nil {
|
||||
h.r.Error(w, req, http.StatusBadRequest, fmt.Errorf("something went wrong when setting the privacy mode: %w", err))
|
||||
}
|
||||
|
||||
// we successfully set the privacy mode! time to redirect to the updated settings overview
|
||||
urlTo := web.NewURLTo(router.CompleteApp())
|
||||
overview := urlTo(router.AdminSettings).String()
|
||||
http.Redirect(w, req, overview, http.StatusFound)
|
||||
}
|
|
@ -123,6 +123,7 @@ ExplanationOpen = "Open invite codes, anyone may connect"
|
|||
ExplanationCommunity = "Members can create invites, anyone may connect"
|
||||
ExplanationRestricted = "Only admins/mods can create invites, only members may connect"
|
||||
|
||||
Settings = "Settings"
|
||||
|
||||
[MemberCount]
|
||||
description = "Number of members"
|
||||
|
|
|
@ -6,9 +6,11 @@ import "github.com/gorilla/mux"
|
|||
|
||||
// constant names for the named routes
|
||||
const (
|
||||
AdminDashboard = "admin:dashboard"
|
||||
AdminDashboardSetPrivacy = "admin:dashboard:set-privacy"
|
||||
AdminMenu = "admin:menu"
|
||||
AdminDashboard = "admin:dashboard"
|
||||
AdminMenu = "admin:menu"
|
||||
|
||||
AdminSettings = "admin:settings:overview"
|
||||
AdminSettingsSetPrivacy = "admin:settings:set-privacy"
|
||||
|
||||
AdminAliasesRevokeConfirm = "admin:aliases:revoke:confirm"
|
||||
AdminAliasesRevoke = "admin:aliases:revoke"
|
||||
|
@ -44,7 +46,9 @@ func Admin(m *mux.Router) *mux.Router {
|
|||
}
|
||||
|
||||
m.Path("/dashboard").Methods("GET").Name(AdminDashboard)
|
||||
m.Path("/dashboard/set-privacy").Methods("POST").Name(AdminDashboardSetPrivacy)
|
||||
|
||||
m.Path("/settings").Methods("GET").Name(AdminSettings)
|
||||
m.Path("/settings/set-privacy").Methods("POST").Name(AdminSettingsSetPrivacy)
|
||||
|
||||
m.Path("/menu").Methods("GET").Name(AdminMenu)
|
||||
|
||||
|
|
|
@ -85,54 +85,5 @@
|
|||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="max-w-lg">
|
||||
<h2 class="text-xl tracking-tight font-bold text-black mt-2 mb-2">{{i18n "PrivacyModesTitle"}}</h2>
|
||||
<p class="mb-4">
|
||||
{{ i18n "ExplanationPrivacyModes" }}
|
||||
<a class="text-pink-600 underline" href="https://ssb-ngi-pointer.github.io/rooms2/#privacy-modes">{{ i18n "RoomsSpecification" }}</a>.
|
||||
</p>
|
||||
<h3 class="text-gray-400 text-sm font-bold mb-2">{{ i18n "SetPrivacyModeTitle" }}</h3>
|
||||
<details class="mb-8 self-start w-96" id="change-privacy">
|
||||
<summary class="px-3 py-1 w-96 rounded shadow bg-white ring-1 ring-gray-300 hover:bg-gray-100 cursor-pointer">
|
||||
{{ i18n .CurrentMode.String }}
|
||||
</summary>
|
||||
|
||||
<div class="absolute w-96 z-10 bg-white mt-2 shadow-xl ring-1 ring-gray-200 rounded divide-y flex flex-col items-stretch overflow-hidden">
|
||||
{{ range .PrivacyModes }}
|
||||
{{ if ne . $.CurrentMode }}
|
||||
<form
|
||||
action="{{urlTo "admin:dashboard:set-privacy" }}"
|
||||
method="POST"
|
||||
>
|
||||
{{$.csrfField}}
|
||||
<input type="hidden" name="privacy_mode" value="{{.}}">
|
||||
<input
|
||||
type="submit"
|
||||
value="{{ i18n .String }}"
|
||||
class="pl-10 pr-3 py-2 w-full text-left bg-white text-gray-700 hover:text-gray-900 hover:bg-gray-50 cursor-pointer"
|
||||
/>
|
||||
</form>
|
||||
{{ else }}
|
||||
<div class="pr-3 py-2 text-gray-600 flex flex-row items-center cursor-default">
|
||||
<div class="w-10 flex flex-row items-center justify-center">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span>{{ i18n .String }}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</details>
|
||||
<div class="grid max-w-lg grid-cols-3 gap-y-2 mb-8">
|
||||
<div class="text-xl text-gray-500 font-bold">Open</div>
|
||||
<div class="text-md col-span-2 italic">{{ i18n "ExplanationOpen" }}</div>
|
||||
<div class="text-xl text-gray-500 font-bold">Community</div>
|
||||
<div class="text-md col-span-2 italic">{{ i18n "ExplanationCommunity" }}</div>
|
||||
<div class="text-xl text-gray-500 font-bold">Restricted</div>
|
||||
<div class="text-md col-span-2 italic">{{ i18n "ExplanationRestricted" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
{{ define "title" }}{{i18n "Settings"}}{{ end }}
|
||||
{{ define "content" }}
|
||||
<h1
|
||||
class="text-3xl tracking-tight font-black text-black mt-2 mb-0"
|
||||
>{{ i18n "Settings" }}</h1>
|
||||
|
||||
<div class="flex flex-col-reverse sm:flex-row justify-start items-stretch ">
|
||||
<div class="max-w-lg">
|
||||
<h2 class="text-xl tracking-tight font-bold text-black mt-2 mb-2">{{ i18n "PrivacyModesTitle" }}</h2>
|
||||
<p class="mb-4">
|
||||
{{ i18n "ExplanationPrivacyModes" }}
|
||||
<a class="text-pink-600 underline" href="https://ssb-ngi-pointer.github.io/rooms2/#privacy-modes">{{ i18n "RoomsSpecification" }}</a>.
|
||||
</p>
|
||||
<h3 class="text-gray-400 text-sm font-bold mb-2">{{ i18n "SetPrivacyModeTitle" }}</h3>
|
||||
<details class="mb-8 self-start w-96" id="change-privacy">
|
||||
<summary class="px-3 py-1 w-96 rounded shadow bg-white ring-1 ring-gray-300 hover:bg-gray-100 cursor-pointer">
|
||||
{{ i18n .CurrentMode.String }}
|
||||
</summary>
|
||||
|
||||
<div class="absolute w-96 z-10 bg-white mt-2 shadow-xl ring-1 ring-gray-200 rounded divide-y flex flex-col items-stretch overflow-hidden">
|
||||
{{ range .PrivacyModes }}
|
||||
{{ if ne . $.CurrentMode }}
|
||||
<form
|
||||
action="{{ urlTo "admin:settings:set-privacy" }}"
|
||||
method="POST"
|
||||
>
|
||||
{{ $.csrfField }}
|
||||
<input type="hidden" name="privacy_mode" value="{{.}}">
|
||||
<input
|
||||
type="submit"
|
||||
value="{{ i18n .String }}"
|
||||
class="pl-10 pr-3 py-2 w-full text-left bg-white text-gray-700 hover:text-gray-900 hover:bg-gray-50 cursor-pointer"
|
||||
/>
|
||||
</form>
|
||||
{{ else }}
|
||||
<div class="pr-3 py-2 text-gray-600 flex flex-row items-center cursor-default">
|
||||
<div class="w-10 flex flex-row items-center justify-center">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span>{{ i18n .String }}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</details>
|
||||
<div class="grid max-w-lg grid-cols-3 gap-y-2 mb-8">
|
||||
<div class="text-xl text-gray-500 font-bold">{{ i18n "ModeOpen" }}</div>
|
||||
<div class="text-md col-span-2 italic">{{ i18n "ExplanationOpen" }}</div>
|
||||
<div class="text-xl text-gray-500 font-bold">{{ i18n "ModeCommunity" }}</div>
|
||||
<div class="text-md col-span-2 italic">{{ i18n "ExplanationCommunity" }}</div>
|
||||
<div class="text-xl text-gray-500 font-bold">{{ i18n "ModeRestricted" }}</div>
|
||||
<div class="text-md col-span-2 italic">{{ i18n "ExplanationRestricted" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
|
@ -46,6 +46,15 @@
|
|||
</svg>{{i18n "AdminDeniedKeysTitle"}}
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="{{urlTo "admin:settings:overview"}}"
|
||||
class="{{if current_page_is "admin:settings:overview"}}bg-gray-300 {{else}}hover:bg-gray-200 {{end}}pr-1 pl-2 py-3 sm:py-1 rounded-md flex flex-row items-center font-semibold text-sm text-gray-700 hover:text-gray-800 truncate"
|
||||
>
|
||||
<svg class="text-green-600 w-4 h-4 mr-1" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M13 3C16.88 3 20 6.14 20 10C20 12.8 18.37 15.19 16 16.31V21H9V18H8C6.89 18 6 17.11 6 16V13H4.5C4.08 13 3.84 12.5 4.08 12.19L6 9.66C6.19 5.95 9.23 3 13 3M13 1C8.42 1 4.61 4.43 4.06 8.91L2.5 11C1.92 11.72 1.82 12.72 2.24 13.59C2.6 14.31 3.24 14.8 4 14.95V16C4 17.86 5.28 19.43 7 19.87V23H18V17.47C20.5 15.83 22 13.06 22 10C22 5.04 17.96 1 13 1M16.1 9.42V9C16.1 8.85 16.1 8.76 16.04 8.62L16.93 7.96C17 7.92 17 7.78 17 7.68L16.18 6.32C16.13 6.23 16 6.18 15.9 6.23L14.91 6.65C14.73 6.46 14.5 6.32 14.26 6.23L14.1 5.2C14.07 5.06 14 5 13.88 5H12.29C12.19 5 12.1 5.06 12.1 5.2L11.96 6.23C11.73 6.32 11.5 6.46 11.3 6.65L10.27 6.23C10.18 6.18 10.1 6.23 10.04 6.32L9.24 7.68C9.19 7.82 9.19 7.92 9.29 7.96L10.13 8.62C10.13 8.76 10.1 8.9 10.1 9C10.1 9.14 10.13 9.28 10.13 9.42L9.29 10.07C9.19 10.12 9.19 10.21 9.24 10.31L10.04 11.71C10.1 11.81 10.18 11.81 10.27 11.81L11.26 11.38C11.5 11.57 11.68 11.67 11.96 11.76L12.1 12.84C12.1 12.93 12.19 13 12.29 13H13.88C14 13 14.07 12.93 14.1 12.84L14.26 11.76C14.5 11.67 14.73 11.57 14.91 11.39L15.9 11.81C16 11.81 16.13 11.81 16.18 11.71L17 10.31C17 10.21 17 10.12 16.93 10.07L16.1 9.42M13.1 10.45C12.32 10.45 11.68 9.79 11.68 9S12.29 7.59 13.1 7.59C13.88 7.59 14.54 8.2 14.54 9S13.88 10.45 13.1 10.45Z" />
|
||||
</svg>{{i18n "Settings"}}
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="{{urlTo "complete:notice:list"}}"
|
||||
class="{{if current_page_is "complete:notice:list"}}bg-gray-300 {{else}}hover:bg-gray-200 {{end}}pr-1 pl-2 py-3 sm:py-1 rounded-md flex flex-row items-center font-semibold text-sm text-gray-700 hover:text-gray-800 truncate"
|
||||
|
@ -55,4 +64,4 @@
|
|||
</svg>{{i18n "NavAdminNotices"}}
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
Loading…
Reference in New Issue