Settings (#44)

* prettier
* remove links
* notifications permissions
This commit is contained in:
Tyr Mactire 2022-08-01 22:45:34 -07:00 committed by GitHub
parent e4a9aa08ab
commit 19720ed3f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 380 additions and 262 deletions

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.18
require (
github.com/contribsys/faktory v1.6.1
github.com/contribsys/faktory_worker_go v1.6.0
github.com/feditools/go-lib v0.15.0
github.com/feditools/go-lib v0.15.1
github.com/go-fed/activity v1.0.0
github.com/go-fed/httpsig v1.1.0
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1

4
go.sum
View File

@ -90,8 +90,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/feditools/go-lib v0.15.0 h1:B1H/Z+nPOYtsXdxrUGcXIrS0QqXQJht1hKPWtRaQBtE=
github.com/feditools/go-lib v0.15.0/go.mod h1:LtdLBvApYAhdblS6rTGQ12ZzySI9/6PyTiZlxw5uX10=
github.com/feditools/go-lib v0.15.1 h1:dd8xiHiizTUBSbS+8FdodbnKUqmYikntWs1vcHGCIMg=
github.com/feditools/go-lib v0.15.1/go.mod h1:LtdLBvApYAhdblS6rTGQ12ZzySI9/6PyTiZlxw5uX10=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=

View File

@ -0,0 +1,13 @@
package template
import "github.com/feditools/relay/internal/models"
// BlocksName is the name of the blocks template.
const BlocksName = "blocks"
// Blocks contains the variables for the blocks template.
type Blocks struct {
Common
Blocks []*models.Block
}

View File

@ -12,5 +12,4 @@ type Home struct {
HomeBody string
FollowingInstances []*models.Instance
Blocks []*models.Block
}

View File

@ -0,0 +1,19 @@
package template
import libtemplate "github.com/feditools/go-lib/template"
// SettingsName is the name of the home template.
const SettingsName = "settings"
// Settings contains the variables for the home template.
type Settings struct {
Common
FormGeneralAccount libtemplate.FormInput
FormGeneralIsMod libtemplate.FormInput
FormGeneralIsAdmin libtemplate.FormInput
FormNotificationDisplay bool
FormNotificationTelegramEnabled libtemplate.FormInput
FormNotificationTelegramChatID libtemplate.FormInput
}

View File

@ -1,14 +0,0 @@
package template
import libtemplate "github.com/feditools/go-lib/template"
// SettingsHomeName is the name of the home template.
const SettingsHomeName = "settings_home"
// SettingsHome contains the variables for the home template.
type SettingsHome struct {
Common
FormNotificationTelegramEnabled libtemplate.FormInput
FormNotificationTelegramChatID libtemplate.FormInput
}

View File

@ -43,7 +43,7 @@ func New(tokz *token.Tokenizer) (*template.Template, error) {
"pathAppHome": path.GenAppHomePath,
"pathAppLogin": path.GenAppLoginPath,
"pathAppLogout": path.GenAppLogoutPath,
"pathAppSettingsHome": path.GenAppSettingsHomePath,
"pathAppSettings": path.GenAppSettingsPath,
"softwareVersion": genString(viper.GetString(config.Keys.SoftwareVersion)),
"urlActor": genActor(domain),
"urlInbox": genInbox(domain),

View File

@ -1,39 +0,0 @@
package webapp
import (
"github.com/feditools/go-lib/language"
"github.com/feditools/relay/internal/http/template"
"github.com/feditools/relay/internal/path"
nethttp "net/http"
)
func makeAdminNavbar(r *nethttp.Request) template.Navbar {
// get localizer
l := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) // nolint
// create navbar
newNavbar := template.Navbar{
{
Text: l.TextConfig(1).String(),
MatchStr: path.ReAppAdminHome,
FAIcon: "gear",
URL: path.AppAdminHome,
},
{
Text: l.TextInstance(2).String(),
MatchStr: path.ReAppAdminInstancesPre,
FAIcon: "server",
URL: path.AppAdminInstance,
},
{
Text: l.TextBlock(2).String(),
MatchStr: path.ReAppAdminBlockPre,
FAIcon: "user-slash",
URL: path.AppAdminBlock,
},
}
newNavbar.ActivateFromPath(r.URL.Path)
return newNavbar
}

View File

@ -83,12 +83,6 @@ func (m *Module) displayAdminBlockList(w http.ResponseWriter, r *http.Request, c
PageTitle: localizer.TextBlock(2).String(),
},
}
err := m.initTemplateAdmin(w, r, tmplVars)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
// create add form inputs
tmplVars.FormAddAction = libtemplate.FormInput{
@ -284,5 +278,5 @@ func (m *Module) displayAdminBlockList(w http.ResponseWriter, r *http.Request, c
}
tmplVars.Pagination = libtemplate.MakePagination(pageConf)
m.executeTemplate(w, template.AdminBlockName, tmplVars)
m.executeTemplate(w, r, template.AdminBlockName, tmplVars)
}

View File

@ -198,12 +198,6 @@ func (m *Module) displayAdminHome(w http.ResponseWriter, r *http.Request, config
Validation: config.FormNotificationTelegramTokenValidation,
},
}
err := m.initTemplateAdmin(w, r, tmplVars)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
// config form values
if (*config.ConfigMap)[models.ConfigHomeBody] != nil {
@ -235,7 +229,7 @@ func (m *Module) displayAdminHome(w http.ResponseWriter, r *http.Request, config
}
}
m.executeTemplate(w, template.AdminHomeName, tmplVars)
m.executeTemplate(w, r, template.AdminHomeName, tmplVars)
}
func (m *Module) adminHomeConfigMap(ctx context.Context) (*models.ConfigMap, error) {

View File

@ -30,12 +30,6 @@ func (m *Module) displayAdminInstance(w http.ResponseWriter, r *http.Request, co
PageTitle: localizer.TextInstance(2).String(),
},
}
err := m.initTemplateAdmin(w, r, tmplVars)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
// alerts
tmplVars.Alerts = config.Alerts
@ -72,5 +66,5 @@ func (m *Module) displayAdminInstance(w http.ResponseWriter, r *http.Request, co
}
tmplVars.Pagination = libtemplate.MakePagination(pageConf)
m.executeTemplate(w, template.AdminInstanceName, tmplVars)
m.executeTemplate(w, r, template.AdminInstanceName, tmplVars)
}

View File

@ -0,0 +1,36 @@
package webapp
import (
"github.com/feditools/go-lib/language"
"github.com/feditools/relay/internal/http/template"
"net/http"
)
// BlocksGetHandler serves the blocks page.
func (m *Module) BlocksGetHandler(w http.ResponseWriter, r *http.Request) {
l := logger.WithField("func", "BlocksGetHandler")
// get localizer
localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) //nolint
// Init template variables
tmplVars := &template.Blocks{
Common: template.Common{
PageTitle: localizer.TextRelay(1).String() + "-" + localizer.TextBlockedDomain(2).String(),
},
}
// add tooltips script
tmplVars.AddFooterExtraScript(JSTooltip())
blocks, err := m.db.ReadBlocks(r.Context())
if err != nil {
l.Errorf("db read blocks: %s", err.Error())
m.returnErrorPage(w, r, http.StatusInternalServerError, localizer.TextErrorDatabase().String())
return
}
tmplVars.Blocks = blocks
m.executeTemplate(w, r, template.BlocksName, tmplVars)
}

View File

@ -14,12 +14,6 @@ func (m *Module) returnErrorPage(w http.ResponseWriter, r *http.Request, code in
// Init template variables
tmplVars := &template.Error{}
err := m.initTemplate(w, r, tmplVars)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// add error css file
signature, err := m.getSignatureCached(strings.TrimPrefix(path.FileErrorCSS, "/"))
@ -53,7 +47,7 @@ func (m *Module) returnErrorPage(w http.ResponseWriter, r *http.Request, code in
}
w.WriteHeader(code)
m.executeTemplate(w, "error", tmplVars)
m.executeTemplate(w, r, "error", tmplVars)
}
func (m *Module) methodNotAllowedHandler() http.Handler {

View File

@ -25,12 +25,6 @@ func (m *Module) HomeGetHandler(w http.ResponseWriter, r *http.Request) {
HomeBody: defaultHomeBody,
}
err := m.initTemplatePublic(w, r, tmplVars)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
// get config
configMap, err := m.logic.GetConfigMap(
@ -66,16 +60,7 @@ func (m *Module) HomeGetHandler(w http.ResponseWriter, r *http.Request) {
}
tmplVars.FollowingInstances = followingInstance
blocks, err := m.db.ReadBlocks(r.Context())
if err != nil {
l.Errorf("db read blocks: %s", err.Error())
m.returnErrorPage(w, r, http.StatusInternalServerError, localizer.TextErrorDatabase().String())
return
}
tmplVars.Blocks = blocks
m.executeTemplate(w, template.HomeName, tmplVars)
m.executeTemplate(w, r, template.HomeName, tmplVars)
}
// ForwardToHomeHandler serves a home forwarder.

View File

@ -83,12 +83,6 @@ func (m *Module) displayLoginPage(w nethttp.ResponseWriter, r *nethttp.Request,
// Init template variables
tmplVars := &template.Login{}
err := m.initTemplate(w, r, tmplVars)
if err != nil {
nethttp.Error(w, err.Error(), nethttp.StatusInternalServerError)
return
}
// add error css file
signature, err := m.getSignatureCached(strings.TrimPrefix(path.FileLoginCSS, "/"))
@ -108,5 +102,5 @@ func (m *Module) displayLoginPage(w nethttp.ResponseWriter, r *nethttp.Request,
tmplVars.FormError = formError
tmplVars.FormAccount = account
m.executeTemplate(w, template.LoginName, tmplVars)
m.executeTemplate(w, r, template.LoginName, tmplVars)
}

View File

@ -69,18 +69,6 @@ func (m *Module) Middleware(next http.Handler) http.Handler {
})
}
// MiddlewareRequireAuth will redirect a user to login page if user not in context.
func (m *Module) MiddlewareRequireAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, shouldReturn := m.authRequireLoggedIn(w, r)
if shouldReturn {
return
}
next.ServeHTTP(w, r)
})
}
// MiddlewareRequireAdmin will redirect a user to login page if user not in context and will return unauthorized for
// a non admin user.
func (m *Module) MiddlewareRequireAdmin(next http.Handler) http.Handler {

View File

@ -0,0 +1,14 @@
package webapp
import "github.com/feditools/relay/internal/models"
func permissionSettingsNotifications(account *models.Account) bool {
switch {
case account.IsAdmin:
return true
case account.IsMod:
return true
default:
return false
}
}

View File

@ -1,10 +0,0 @@
package webapp
import (
"github.com/feditools/relay/internal/http/template"
"net/http"
)
func makePublicNavbar(_ *http.Request) template.Navbar {
return template.Navbar{}
}

View File

@ -16,21 +16,16 @@ func (m *Module) Route(s *http.Server) error {
webapp.NotFoundHandler = m.notFoundHandler()
webapp.MethodNotAllowedHandler = m.methodNotAllowedHandler()
webapp.HandleFunc(path.AppSubBlocks, m.BlocksGetHandler).Methods(nethttp.MethodGet)
webapp.HandleFunc(path.AppSubCallbackOauth, m.CallbackOauthGetHandler).Methods(nethttp.MethodGet)
webapp.HandleFunc(path.AppSubHome, m.HomeGetHandler).Methods(nethttp.MethodGet)
webapp.HandleFunc(path.AppSubLogin, m.LoginGetHandler).Methods(nethttp.MethodGet)
webapp.HandleFunc(path.AppSubLogin, m.LoginPostHandler).Methods(nethttp.MethodPost)
webapp.HandleFunc(path.AppSubLogout, m.LogoutGetHandler).Methods(nethttp.MethodGet)
webapp.HandleFunc(path.AppSubSettings, m.SettingsGetHandler).Methods(nethttp.MethodGet)
webapp.HandleFunc(path.AppSubSettings, m.SettingsPostHandler).Methods(nethttp.MethodPost)
settings := webapp.PathPrefix(path.AppSubSettings).Subrouter()
settings.Use(m.MiddlewareRequireAuth)
settings.NotFoundHandler = m.notFoundHandler()
settings.MethodNotAllowedHandler = m.methodNotAllowedHandler()
settings.HandleFunc(path.AppSettingsSubHome, m.SettingsHomeGetHandler).Methods(nethttp.MethodGet)
settings.HandleFunc(path.AppSettingsSubHome, m.SettingsHomePostHandler).Methods(nethttp.MethodPost)
admin := webapp.PathPrefix(path.AppAdmin).Subrouter()
admin := webapp.PathPrefix(path.AppSubAdmin).Subrouter()
admin.Use(m.MiddlewareRequireAdmin)
admin.NotFoundHandler = m.notFoundHandler()
admin.MethodNotAllowedHandler = m.methodNotAllowedHandler()

View File

@ -2,6 +2,7 @@ package webapp
import (
"context"
"fmt"
"github.com/feditools/go-lib/language"
libtemplate "github.com/feditools/go-lib/template"
"github.com/feditools/relay/internal/http/template"
@ -9,10 +10,15 @@ import (
"net/http"
)
// SettingsHomeGetHandler serves the home page.
func (m *Module) SettingsHomeGetHandler(w http.ResponseWriter, r *http.Request) {
// SettingsGetHandler serves the home page.
func (m *Module) SettingsGetHandler(w http.ResponseWriter, r *http.Request) {
l := logger.WithField("func", "SettingsHomeGetHandler")
_, shouldReturn := m.authRequireLoggedIn(w, r)
if shouldReturn {
return
}
// get localizer
localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) //nolint
@ -33,10 +39,15 @@ func (m *Module) SettingsHomeGetHandler(w http.ResponseWriter, r *http.Request)
})
}
// SettingsHomePostHandler serves the home page.
func (m *Module) SettingsHomePostHandler(w http.ResponseWriter, r *http.Request) {
// SettingsPostHandler serves the home page.
func (m *Module) SettingsPostHandler(w http.ResponseWriter, r *http.Request) {
l := logger.WithField("func", "SettingsHomePostHandler")
_, shouldReturn := m.authRequireLoggedIn(w, r)
if shouldReturn {
return
}
// get localizer
localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) //nolint
@ -57,24 +68,26 @@ func (m *Module) SettingsHomePostHandler(w http.ResponseWriter, r *http.Request)
// gather changes
var changes []*models.ConfigChange
err = m.settingsHomeFormTelegramEnabled(r, configMap, &changes)
if err != nil {
l.Errorf("form home body: %s", err.Error())
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
if permissionSettingsNotifications(account) {
err = m.settingsFormTelegramEnabled(r, configMap, &changes)
if err != nil {
l.Errorf("form home body: %s", err.Error())
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
err = m.settingsHomeFormTelegramChatID(r, configMap, &changes)
if err != nil {
l.Errorf("form telegram enabled: %s", err.Error())
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
err = m.settingsFormTelegramChatID(r, configMap, &changes)
if err != nil {
l.Errorf("form telegram enabled: %s", err.Error())
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
return
}
}
displayConfig.ConfigMap = configMap
// validate form
valid, err := settingsHomeFormValidate(configMap, &displayConfig)
valid, err := settingsFormValidate(configMap, &displayConfig)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
@ -109,6 +122,13 @@ func (m *Module) SettingsHomePostHandler(w http.ResponseWriter, r *http.Request)
Text: "config updated",
},
}
} else {
displayConfig.Alerts = &[]libtemplate.Alert{
{
Color: libtemplate.ColorWarning,
Text: "no changes detected",
},
}
}
m.displaySettingsHome(w, r, displayConfig)
@ -128,13 +148,51 @@ func (m *Module) displaySettingsHome(w http.ResponseWriter, r *http.Request, con
// get localizer
localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) //nolint
// account
account := r.Context().Value(ContextKeyAccount).(*models.Account) //nolint
// Init template variables
tmplVars := &template.SettingsHome{
tmplVars := &template.Settings{
Common: template.Common{
Alerts: config.Alerts,
PageTitle: localizer.TextRelay(1).String(),
},
FormGeneralAccount: libtemplate.FormInput{
ID: "formGeneralAccount",
Type: libtemplate.FormInputTypeText,
Label: &libtemplate.FormLabel{
Text: localizer.TextAccount(1),
Class: "form-label",
},
Disabled: true,
Required: false,
Value: fmt.Sprintf("%s@%s", account.Username, account.Instance.Domain),
},
FormGeneralIsMod: libtemplate.FormInput{
ID: "formGeneralIsMod",
Type: libtemplate.FormInputTypeCheckbox,
Label: &libtemplate.FormLabel{
Text: localizer.TextModerator(1),
Class: "form-check-label",
},
Disabled: true,
Required: false,
Checked: account.IsMod,
},
FormGeneralIsAdmin: libtemplate.FormInput{
ID: "formGeneralIsAdmin",
Type: libtemplate.FormInputTypeCheckbox,
Label: &libtemplate.FormLabel{
Text: localizer.TextAdmin(),
Class: "form-check-label",
},
Disabled: true,
Required: false,
Checked: account.IsAdmin,
},
FormNotificationDisplay: permissionSettingsNotifications(account),
FormNotificationTelegramEnabled: libtemplate.FormInput{
ID: "formNotificationTelegramEnabled",
Type: libtemplate.FormInputTypeCheckbox,
@ -151,7 +209,7 @@ func (m *Module) displaySettingsHome(w http.ResponseWriter, r *http.Request, con
Type: libtemplate.FormInputTypeText,
Name: FormTelegramChatID,
Label: &libtemplate.FormLabel{
Text: localizer.TextChatIDOrUsername(),
Text: localizer.TextChatID(1),
Class: "form-label",
},
Disabled: false,
@ -159,12 +217,6 @@ func (m *Module) displaySettingsHome(w http.ResponseWriter, r *http.Request, con
Validation: config.FormNotificationTelegramChatIDValidation,
},
}
err := m.initTemplatePublic(w, r, tmplVars)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
// config form values
if (*config.ConfigMap)[models.ConfigUserTelegramEnabled] != nil {
@ -190,7 +242,7 @@ func (m *Module) displaySettingsHome(w http.ResponseWriter, r *http.Request, con
tmplVars.FormNotificationTelegramChatID.Value = value
}
m.executeTemplate(w, template.SettingsHomeName, tmplVars)
m.executeTemplate(w, r, template.SettingsName, tmplVars)
}
func (m *Module) settingsHomeConfigMap(ctx context.Context, accountID int64) (*models.ConfigMap, error) {

View File

@ -6,8 +6,8 @@ import (
"net/http"
)
func (m *Module) settingsHomeFormTelegramEnabled(r *http.Request, cm *models.ConfigMap, changes *[]*models.ConfigChange) error {
l := logger.WithField("func", "settingsHomeFormTelegramEnabled")
func (m *Module) settingsFormTelegramEnabled(r *http.Request, cm *models.ConfigMap, changes *[]*models.ConfigChange) error {
l := logger.WithField("func", "settingsFormTelegramEnabled")
formValue := r.FormValue(FormTelegramEnabled)
switch {
@ -90,8 +90,8 @@ func (m *Module) settingsHomeFormTelegramEnabled(r *http.Request, cm *models.Con
return nil
}
func (m *Module) settingsHomeFormTelegramChatID(r *http.Request, cm *models.ConfigMap, changes *[]*models.ConfigChange) error {
l := logger.WithField("func", "settingsHomeFormTelegramChatID")
func (m *Module) settingsFormTelegramChatID(r *http.Request, cm *models.ConfigMap, changes *[]*models.ConfigChange) error {
l := logger.WithField("func", "settingsFormTelegramChatID")
formValue := r.FormValue(FormTelegramChatID)
switch {
@ -161,8 +161,8 @@ func (m *Module) settingsHomeFormTelegramChatID(r *http.Request, cm *models.Conf
return nil
}
func settingsHomeFormValidate(cm *models.ConfigMap, displayConfig *displaySettingsHomeConfig) (bool, error) {
l := logger.WithField("func", "settingsHomeFormValidate")
func settingsFormValidate(cm *models.ConfigMap, displayConfig *displaySettingsHomeConfig) (bool, error) {
l := logger.WithField("func", "settingsFormValidate")
valid := true

View File

@ -5,18 +5,26 @@ import (
"github.com/feditools/go-lib/language"
"github.com/feditools/relay/internal/http/template"
"github.com/feditools/relay/internal/models"
"github.com/feditools/relay/internal/path"
"github.com/sirupsen/logrus"
"net/http"
)
func (m *Module) executeTemplate(w http.ResponseWriter, name string, tmplVars interface{}) {
func (m *Module) executeTemplate(w http.ResponseWriter, r *http.Request, name string, tmplVars template.InitTemplate) {
l := logger.WithFields(logrus.Fields{
"func": "executeTemplate",
"template": name,
})
err := m.initTemplate(w, r, tmplVars)
if err != nil {
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
return
}
b := new(bytes.Buffer)
err := m.templates.ExecuteTemplate(b, name, tmplVars)
err = m.templates.ExecuteTemplate(b, name, tmplVars)
if err != nil {
l.Errorf("could not render template: %s", err.Error())
@ -64,49 +72,95 @@ func (m *Module) initTemplate(_ http.ResponseWriter, r *http.Request, tmpl templ
tmpl.SetAccount(account)
}
// try to read session data
/*if r.Context().Value(http.ContextKeySession) == nil {
return nil
}
us := r.Context().Value(http.ContextKeySession).(*sessions.Session)
saveSession := false
if saveSession {
err := us.Save(r, w)
if err != nil {
l.Warningf("initTemplate could not save session: %s", err.Error())
return err
}
}*/
return nil
}
func (m *Module) initTemplateAdmin(w http.ResponseWriter, r *http.Request, tmpl template.InitTemplate) error {
err := m.initTemplate(w, r, tmpl)
// make navbar
navbar, err := m.makeNavbar(r)
if err != nil {
return err
}
// make admin navbar
navbar := makeAdminNavbar(r)
tmpl.SetNavbarDark(true)
tmpl.SetNavbar(navbar)
return nil
}
func (m *Module) initTemplatePublic(w http.ResponseWriter, r *http.Request, tmpl template.InitTemplate) error {
err := m.initTemplate(w, r, tmpl)
if err != nil {
return err
}
// make admin navbar
navbar := makePublicNavbar(r)
tmpl.SetNavbarDark(false)
tmpl.SetNavbar(navbar)
return nil
}
func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
log := logger.WithField("func", "displayAdminBlockList")
// get localizer
l := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) // nolint
// create navbar
newNavbar := template.Navbar{
{
Text: l.TextHomeWeb().String(),
MatchStr: path.ReAppHome,
FAIcon: "house",
URL: path.AppHome,
},
}
// show blocks page if any exist
blockCount, err := m.db.CountBlocks(r.Context())
if err != nil {
log.Errorf("db count: %s", err.Error())
return nil, err
}
if blockCount > 0 {
newNode := template.NavbarNode{
Text: l.TextBlock(2).String(),
MatchStr: path.ReAppBlocks,
FAIcon: "user-slash",
URL: path.AppBlocks,
}
newNavbar = append(newNavbar, newNode)
}
// get account
account, loggedIn := r.Context().Value(ContextKeyAccount).(*models.Account)
if loggedIn {
newNode := template.NavbarNode{
Text: l.TextSetting(2).String(),
MatchStr: path.ReAppSettings,
FAIcon: "gear",
URL: path.AppSettings,
}
newNavbar = append(newNavbar, newNode)
if account.IsAdmin || account.IsMod {
newNode := template.NavbarNode{
Text: l.TextAdmin().String(),
MatchStr: path.ReAppAdminPre,
FAIcon: "screwdriver-wrench",
URL: path.AppAdminHome,
Children: template.Navbar{
{
Text: l.TextConfig(1).String(),
MatchStr: path.ReAppAdminHome,
FAIcon: "gear",
URL: path.AppAdminHome,
},
{
Text: l.TextInstance(2).String(),
MatchStr: path.ReAppAdminInstancesPre,
FAIcon: "server",
URL: path.AppAdminInstance,
},
{
Text: l.TextBlock(2).String(),
MatchStr: path.ReAppAdminBlockPre,
FAIcon: "user-slash",
URL: path.AppAdminBlock,
},
},
}
newNavbar = append(newNavbar, newNode)
}
}
newNavbar.ActivateFromPath(r.URL.Path)
return newNavbar, nil
}

View File

@ -42,9 +42,9 @@ func GenAppLogoutPath() string {
return AppLogout
}
// GenAppSettingsHomePath returns a path for the settings page.
func GenAppSettingsHomePath() string {
return AppSettingsHome
// GenAppSettingsPath returns a path for the settings page.
func GenAppSettingsPath() string {
return AppSettings
}
// urls

View File

@ -9,6 +9,8 @@ const (
PartApp = "app"
// PartBlock is used in a path for block.
PartBlock = "block"
// PartBlocks is used in a path for blocks.
PartBlocks = "blocks"
// PartCallback is used in a path for callback.
PartCallback = "callback"
// PartExport is used in a path for export.
@ -39,7 +41,4 @@ const (
PartWebFinger = "webfinger"
// PartWellKnown is the noun used in a well known path
PartWellKnown = ".well-known"
SuffixJSON = "json"
SuffixJCSV = "csv"
)

View File

@ -8,6 +8,10 @@ const (
// App is the path for the web app.
App = "/" + PartApp
// AppBlocks is the path for the blocks page.
AppBlocks = App + AppSubBlocks
// AppSubBlocks is the sub path for the blocks page.
AppSubBlocks = "/" + PartBlocks
// AppCallbackOauth is the path for an oauth callback.
AppCallbackOauth = App + AppSubCallbackOauth
// AppSubCallbackOauth is the sub path for an oauth callback.
@ -30,37 +34,35 @@ const (
AppSettings = App + AppSubSettings
// AppSubSettings is the sub path for the settings page.
AppSubSettings = "/" + PartSettings
// AppSettingsHome is the path for the home page.
AppSettingsHome = AppSettings + AppSettingsSubHome
// AppSettingsSubHome is the sub path for the home page.
AppSettingsSubHome = "/"
// admin
// AppAdmin is the path for the admin page.
AppAdmin = "/" + PartAdmin
AppAdmin = App + "/" + PartAdmin
// AppSubAdmin is the sub path for the admin page.
AppSubAdmin = "/" + PartAdmin
// AppAdminBlock is the path for the admin blocks page.
AppAdminBlock = App + AppAdmin + AppAdminSubBlock
AppAdminBlock = AppAdmin + AppAdminSubBlock
// AppAdminSubBlock is the sub path for the admin blocks page.
AppAdminSubBlock = "/" + PartBlock
// AppAdminBlockExport is the path for the admin blocks export page.
AppAdminBlockExport = App + AppAdmin + AppAdminSubBlockExport
AppAdminBlockExport = AppAdmin + AppAdminSubBlockExport
// AppAdminSubBlockExport is the sub path for the admin blocks export page.
AppAdminSubBlockExport = AppAdminSubBlock + "/" + PartExport
// AppAdminBlockExportCSV is the path for the admin blocks export page.
AppAdminBlockExportCSV = App + AppAdmin + AppAdminSubBlockExportCSV
AppAdminBlockExportCSV = AppAdmin + AppAdminSubBlockExportCSV
// AppAdminSubBlockExportCSV is the sub path for the admin blocks export page.
AppAdminSubBlockExportCSV = AppAdminSubBlockExport + "." + string(libhttp.SuffixTextCSV)
// AppAdminBlockExportJSON is the path for the admin blocks export page.
AppAdminBlockExportJSON = App + AppAdmin + AppAdminSubBlockExportJSON
AppAdminBlockExportJSON = AppAdmin + AppAdminSubBlockExportJSON
// AppAdminSubBlockExportJSON is the sub path for the admin blocks export page.
AppAdminSubBlockExportJSON = AppAdminSubBlockExport + "." + string(libhttp.SuffixAppJSON)
// AppAdminHome is the path for the home page.
AppAdminHome = App + AppAdmin + AppAdminSubHome
AppAdminHome = AppAdmin + AppAdminSubHome
// AppAdminSubHome is the sub path for the home page.
AppAdminSubHome = "/"
// AppAdminInstance is the path for the admin instances page.
AppAdminInstance = App + AppAdmin + AppAdminSubInstance
AppAdminInstance = AppAdmin + AppAdminSubInstance
// AppAdminSubInstance is the sub path for the admin instances page.
AppAdminSubInstance = "/" + PartInstance
)

View File

@ -11,6 +11,8 @@ const (
)
var (
// ReAppAdminPre matches the admin home page.
ReAppAdminPre = regexp.MustCompile(fmt.Sprintf(`^?%s`, AppAdmin))
// ReAppAdminHome matches the admin home page.
ReAppAdminHome = regexp.MustCompile(fmt.Sprintf(`^?%s$`, AppAdminHome))
// ReAppAdminBlockPre matches the admin block page.
@ -18,6 +20,10 @@ var (
// ReAppAdminInstancesPre matches the admin instances page.
ReAppAdminInstancesPre = regexp.MustCompile(fmt.Sprintf(`^?%s`, AppAdminInstance))
// ReAppBlocks matches the blocks page.
ReAppBlocks = regexp.MustCompile(fmt.Sprintf(`^?%s$`, AppBlocks))
// ReAppHome matches the Home page.
ReAppHome = regexp.MustCompile(fmt.Sprintf(`^?%s$`, AppHome))
// ReAppSettings matches the settings page.
ReAppSettings = regexp.MustCompile(fmt.Sprintf(`^?%s$`, AppSettings))
)

View File

@ -83,6 +83,9 @@ Login: Login
Logout: Logout
LooksGood: Looks Good!
Moderation: Moderation
Moderator:
one: Moderator
other: Moderators
Notification:
one: Notification
other: Notifications

View File

@ -21,3 +21,25 @@ func (l *Localizer) TextModeration() *LocalizedString {
string: text,
}
}
// TextModerator returns a translated phrase.
func (l *Localizer) TextModerator(count int) *LocalizedString {
lg := logger.WithField("func", "TextModerator")
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
DefaultMessage: &i18n.Message{
ID: "Moderator",
One: "Moderator",
Other: "Moderators",
},
PluralCount: count,
})
if err != nil {
lg.Warningf(missingTranslationWarning, err.Error())
}
return &LocalizedString{
language: tag,
string: text,
}
}

View File

@ -4,7 +4,7 @@
{{ template "form_label" . }}
{{- end }}
{{- end }}
<input type="{{ .Type }}" class="{{ formInputClass .Type }}{{ if .Validation}}{{ if .Validation.Valid}} is-valid{{ else }} is-invalid{{ end }}{{ end }}" id="{{ .ID }}" name="{{ .Name }}"{{ if ne .Placeholder "" }} placeholder="{{ .Placeholder }}"{{ end }}{{ if ne .Value "" }} value="{{ .Value }}"{{ end }}{{ if .Checked }} checked{{ end }}{{ if .Disabled }} disabled{{ end }}{{ if .Required }} required{{ end }}>
<input type="{{ .Type }}" class="{{ formInputClass .Type }}{{ if .Validation }}{{ if .Validation.Valid }} is-valid{{ else }} is-invalid{{ end }}{{ end }}" id="{{ .ID }}"{{ if .Name }} name="{{ .Name }}"{{ end }}{{ if .Placeholder }} placeholder="{{ .Placeholder }}"{{ end }}{{ if .Value }} value="{{ .Value }}"{{ end }}{{ if .Checked }} checked{{ end }}{{ if .Disabled }} disabled{{ end }}{{ if .Required }} required{{ end }}>
{{- if .Label }}
{{- if formInputLabelDisplayBottom .Type }}
{{ template "form_label" . }}

2
vendor/modules.txt vendored
View File

@ -21,7 +21,7 @@ github.com/dgryski/go-rendezvous
# github.com/fatih/color v1.13.0
## explicit; go 1.13
github.com/fatih/color
# github.com/feditools/go-lib v0.15.0
# github.com/feditools/go-lib v0.15.1
## explicit; go 1.17
github.com/feditools/go-lib
github.com/feditools/go-lib/database

View File

@ -17,7 +17,7 @@
<h1 lang="{{ $textBlock.Language }}"><i class="fa-solid fa-arrows-turn-to-dots"></i> {{ $textBlock }}</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group">
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addModal">
<button type="button" class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#addModal">
<i class="fa-solid fa-plus"></i>
</button>
<button type="button" class="btn btn-outline-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
@ -25,6 +25,7 @@
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="javascript:void(0)" data-bs-toggle="modal" data-bs-target="#importModal">Import</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ pathAppAdminBlockExport }}">Export TXT</a></li>
<li><a class="dropdown-item" href="{{ pathAppAdminBlockExportCSV }}">Export CSV</a></li>
<li><a class="dropdown-item" href="{{ pathAppAdminBlockExportJSON }}">Export JSON</a></li>

View File

@ -0,0 +1,30 @@
{{ define "blocks" -}}
{{- $textBlockedDomains := .Localizer.TextBlockedDomain 2 -}}
{{- template "header" . }}
<div class="container">
<div class="row">
<div class="col d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 lang="{{ $textBlockedDomains.Language }}"><i class="fa-solid fa-user-slash"></i> {{ $textBlockedDomains }}</h1>
</div>
</div>
<div class="row">
<div class="col">
These domains have been blocked from participating on this relay.
</div>
</div>
<div class="row">
<div class="col">
<ul>
{{- range $block := .Blocks }}
{{- if $block.ObfuscatedDomain }}
<li><span data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="{{ $block.Domain }}" data-bs-custom-class="danger-tooltip">{{ $block.ObfuscatedDomain }}</span></li>
{{- else }}
<li>{{ $block.Domain }}</li>
{{- end }}
{{- end }}
</ul>
</div>
</div>
</div><!-- /.container -->
{{ template "footer" . }}
{{ end }}

View File

@ -3,9 +3,9 @@
<div class="container">
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
<p class="col-md-4 mb-0 text-muted">{{ applicationName }} {{ softwareVersion }}</p>
<a href="{{ pathAppHome }}" class="col-md-4 d-flex align-items-center justify-content-center mb-3 mb-md-0 me-md-auto link-dark text-decoration-none">
<div class="col-md-4 d-flex align-items-center justify-content-center mb-3 mb-md-0 me-md-auto link-dark text-decoration-none">
<img src="{{ logoSrcDark }}" class="bi me-2" alt="robot" height="32">
</a>
</div>
<ul class="nav col-md-4 justify-content-end">
<li class="nav-item"><a href="{{ pathAppHome }}" class="nav-link px-2 text-muted">Home</a></li>
<li class="nav-item"><a href="{{ applicationWebsite }}" class="nav-link px-2 text-muted">Repo</a></li>

View File

@ -42,26 +42,6 @@
</ul>
</div>
</div>
{{- if .Blocks }}
<div class="row">
<div class="col mt-4">
<h2 lang="{{ $textBlockedDomains.Language }}"><i class="fa-solid fa-user-slash"></i> {{ $textBlockedDomains }}</h2>
</div>
</div>
<div class="row">
<div class="col">
<ul>
{{- range $block := .Blocks }}
{{- if $block.ObfuscatedDomain }}
<li><span data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="{{ $block.Domain }}" data-bs-custom-class="danger-tooltip">{{ $block.ObfuscatedDomain }}</span></li>
{{- else }}
<li>{{ $block.Domain }}</li>
{{- end }}
{{- end }}
</ul>
</div>
</div>
{{- end }}
</div><!-- /.container -->
{{ template "footer" . }}
{{ end }}

View File

@ -6,10 +6,10 @@
{{- $textLogout := .Localizer.TextLogout }}
<nav class="navbar navbar-expand-lg {{ if .NavBarDark }}navbar-dark bg-primary{{ else }}bg-light{{ end }}">
<div class="container-fluid">
<a class="navbar-brand" href="{{ pathAppHome }}">
<div class="navbar-brand">
<img src="{{ if .NavBarDark }}{{ logoSrcLight }}{{ else }}{{ logoSrcDark }}{{ end }}" alt="robot" height="25" class="d-inline-block align-top">
<span lang="{{ $textRelay.Language }}">{{ $textRelay }}</span>
</a>
</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
@ -48,11 +48,6 @@
<i class="fas fa-user"></i> {{ .Account.Username }}@{{ .Account.Instance.Domain }}
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="{{ pathAppSettingsHome }}" lang="{{ $textSetting.Language }}"><i class="fas fa-gear"></i> {{ $textSetting }}</a></li>
{{- if .Account.IsAdmin }}
<li><a class="dropdown-item" href="{{ pathAppAdminHome }}" lang="{{ $textAdmin.Language }}"><i class="fas fa-screwdriver-wrench"></i> {{ $textAdmin }}</a></li>
{{- end }}
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ pathAppLogout }}" lang="{{ $textLogout.Language }}"><i class="fas fa-sign-out-alt"></i> {{ $textLogout }}</a></li>
</ul>
</li>

View File

@ -1,9 +1,9 @@
{{ define "settings_home" -}}
{{ define "settings" -}}
{{- $textClose := .Localizer.TextClose -}}
{{- $textGeneral := .Localizer.TextGeneral -}}
{{- $textNotifications := .Localizer.TextNotification 2 -}}
{{- $textSave := .Localizer.TextSave -}}
{{- $textSetting := .Localizer.TextSetting 1 -}}
{{- $textSetting := .Localizer.TextSetting 2 -}}
{{- template "header" . }}
<div class="container">
<form method="post">
@ -12,6 +12,23 @@
<h1 lang="{{ $textSetting.Language }}"><i class="fa-solid fa-gear"></i> {{ $textSetting }}</h1>
</div>
</div>
<div class="row">
<div class="col-lg-3 mb-3">
<h2 lang="{{ $textGeneral.Language }}">{{ $textGeneral }}</h2>
</div>
<div class="col mb-3">
<div class="mb-3">
{{ template "form_input" .FormGeneralAccount }}
</div>
<div>
{{ template "form_input" .FormGeneralIsMod }}
</div>
<div class="mb-3">
{{ template "form_input" .FormGeneralIsAdmin }}
</div>
</div>
</div>
{{- if .FormNotificationDisplay }}
<div class="row">
<div class="col-lg-3 mb-3">
<h2 lang="{{ $textNotifications.Language }}">{{ $textNotifications }}</h2>
@ -28,6 +45,7 @@
</div>
</div>
</div>
{{- end }}
<div class="row">
<div class="col-lg-3 mb-3"></div>
<div class="col mb-3">