Various fixes
* fix accept and consumed view * Apply suggestions from Alex' code review * define admin.Databases options struct * structify database parameters of web/handlers
This commit is contained in:
parent
672647cd4d
commit
fd21dfc60a
|
@ -155,6 +155,9 @@ func (i Invites) GetByToken(ctx context.Context, token string) (admindb.Invite,
|
|||
qm.Load("CreatedByAuthFallback"),
|
||||
).One(ctx, i.db)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return inv, admindb.ErrNotFound
|
||||
}
|
||||
return inv, err
|
||||
}
|
||||
|
||||
|
@ -174,6 +177,9 @@ func (i Invites) GetByID(ctx context.Context, id int64) (admindb.Invite, error)
|
|||
qm.Load("CreatedByAuthFallback"),
|
||||
).One(ctx, i.db)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return inv, admindb.ErrNotFound
|
||||
}
|
||||
return inv, err
|
||||
}
|
||||
|
||||
|
@ -225,6 +231,9 @@ func (i Invites) Revoke(ctx context.Context, id int64) error {
|
|||
qm.Where("active = true AND id = ?", id),
|
||||
).One(ctx, tx)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return admindb.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -215,12 +215,14 @@ func runroomsrv() error {
|
|||
repo.New(repoDir),
|
||||
httpsDomain,
|
||||
roomsrv.StateManager,
|
||||
db.AuthWithSSB,
|
||||
db.AuthFallback,
|
||||
db.AllowList,
|
||||
db.Invites,
|
||||
db.Notices,
|
||||
db.PinnedNotices,
|
||||
handlers.Databases{
|
||||
AuthWithSSB: db.AuthWithSSB,
|
||||
AuthFallback: db.AuthFallback,
|
||||
AllowList: db.AllowList,
|
||||
Invites: db.Invites,
|
||||
Notices: db.Notices,
|
||||
PinnedNotices: db.PinnedNotices,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create HTTPdashboard handler: %w", err)
|
||||
|
|
|
@ -96,10 +96,12 @@ func newSession(t *testing.T) *testSession {
|
|||
ts.Domain,
|
||||
r,
|
||||
ts.RoomState,
|
||||
ts.AllowListDB,
|
||||
ts.InvitesDB,
|
||||
ts.NoticeDB,
|
||||
ts.PinnedDB,
|
||||
Databases{
|
||||
AllowList: ts.AllowListDB,
|
||||
Invites: ts.InvitesDB,
|
||||
Notices: ts.NoticeDB,
|
||||
PinnedNotices: ts.PinnedDB,
|
||||
},
|
||||
)
|
||||
|
||||
handler = user.MiddlewareForTests(ts.User)(handler)
|
||||
|
|
|
@ -32,16 +32,21 @@ var HTMLTemplates = []string{
|
|||
"admin/notice-edit.tmpl",
|
||||
}
|
||||
|
||||
// Databases is an option struct that encapsualtes the required database services
|
||||
type Databases struct {
|
||||
AllowList admindb.AllowListService
|
||||
Invites admindb.InviteService
|
||||
Notices admindb.NoticesService
|
||||
PinnedNotices admindb.PinnedNoticesService
|
||||
}
|
||||
|
||||
// Handler supplies the elevated access pages to known users.
|
||||
// It is not registering on the mux router like other pages to clean up the authorize flow.
|
||||
func Handler(
|
||||
domainName string,
|
||||
r *render.Renderer,
|
||||
roomState *roomstate.Manager,
|
||||
al admindb.AllowListService,
|
||||
is admindb.InviteService,
|
||||
ndb admindb.NoticesService,
|
||||
pdb admindb.PinnedNoticesService,
|
||||
dbs Databases,
|
||||
) http.Handler {
|
||||
mux := &http.ServeMux{}
|
||||
// TODO: configure 404 handler
|
||||
|
@ -59,7 +64,7 @@ func Handler(
|
|||
|
||||
var ah = allowListHandler{
|
||||
r: r,
|
||||
al: al,
|
||||
al: dbs.AllowList,
|
||||
}
|
||||
mux.HandleFunc("/members", r.HTML("admin/allow-list.tmpl", ah.overview))
|
||||
mux.HandleFunc("/members/add", ah.add)
|
||||
|
@ -68,7 +73,7 @@ func Handler(
|
|||
|
||||
var ih = invitesHandler{
|
||||
r: r,
|
||||
db: is,
|
||||
db: dbs.Invites,
|
||||
|
||||
domainName: domainName,
|
||||
}
|
||||
|
@ -79,8 +84,8 @@ func Handler(
|
|||
|
||||
var nh = noticeHandler{
|
||||
r: r,
|
||||
noticeDB: ndb,
|
||||
pinnedDB: pdb,
|
||||
noticeDB: dbs.Notices,
|
||||
pinnedDB: dbs.PinnedNotices,
|
||||
}
|
||||
mux.HandleFunc("/notice/edit", r.HTML("admin/notice-edit.tmpl", nh.edit))
|
||||
mux.HandleFunc("/notice/translation/draft", r.HTML("admin/notice-edit.tmpl", nh.draftTranslation))
|
||||
|
|
|
@ -39,18 +39,24 @@ var HTMLTemplates = []string{
|
|||
"error.tmpl",
|
||||
}
|
||||
|
||||
// Databases is an options stuct for the required databases of the web handlers
|
||||
type Databases struct {
|
||||
AuthWithSSB admindb.AuthWithSSBService
|
||||
AuthFallback admindb.AuthFallbackService
|
||||
AllowList admindb.AllowListService
|
||||
Invites admindb.InviteService
|
||||
Notices admindb.NoticesService
|
||||
PinnedNotices admindb.PinnedNoticesService
|
||||
}
|
||||
|
||||
// New initializes the whole web stack for rooms, with all the sub-modules and routing.
|
||||
func New(
|
||||
logger logging.Interface,
|
||||
repo repo.Interface,
|
||||
domainName string,
|
||||
roomState *roomstate.Manager,
|
||||
as admindb.AuthWithSSBService,
|
||||
fs admindb.AuthFallbackService,
|
||||
al admindb.AllowListService,
|
||||
is admindb.InviteService,
|
||||
ns admindb.NoticesService,
|
||||
ps admindb.PinnedNoticesService,
|
||||
dbs Databases,
|
||||
|
||||
) (http.Handler, error) {
|
||||
m := router.CompleteApp()
|
||||
|
||||
|
@ -93,7 +99,7 @@ func New(
|
|||
if !noticeName.Valid() {
|
||||
return nil
|
||||
}
|
||||
notice, err := ps.Get(r.Context(), noticeName, "en-GB")
|
||||
notice, err := dbs.PinnedNotices.Get(r.Context(), noticeName, "en-GB")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -173,7 +179,7 @@ func New(
|
|||
}, nil
|
||||
})
|
||||
|
||||
a, err := auth.NewHandler(fs,
|
||||
a, err := auth.NewHandler(dbs.AuthFallback,
|
||||
auth.SetStore(store),
|
||||
auth.SetErrorHandler(authErrH),
|
||||
auth.SetNotAuthorizedHandler(notAuthorizedH),
|
||||
|
@ -204,18 +210,21 @@ func New(
|
|||
// hookup handlers to the router
|
||||
roomsAuth.Handler(m, r, a)
|
||||
|
||||
adminHandler := a.Authenticate(admin.Handler(
|
||||
adminHandler := admin.Handler(
|
||||
domainName,
|
||||
r,
|
||||
roomState,
|
||||
al,
|
||||
is,
|
||||
ns,
|
||||
ps))
|
||||
mainMux.Handle("/admin/", adminHandler)
|
||||
admin.Databases{
|
||||
AllowList: dbs.AllowList,
|
||||
Invites: dbs.Invites,
|
||||
Notices: dbs.Notices,
|
||||
PinnedNotices: dbs.PinnedNotices,
|
||||
},
|
||||
)
|
||||
mainMux.Handle("/admin/", a.Authenticate(adminHandler))
|
||||
|
||||
m.Get(router.CompleteIndex).Handler(r.HTML("landing/index.tmpl", func(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
notice, err := ps.Get(req.Context(), admindb.NoticeDescription, "en-GB")
|
||||
notice, err := dbs.PinnedNotices.Get(req.Context(), admindb.NoticeDescription, "en-GB")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find description: %w", err)
|
||||
}
|
||||
|
@ -230,14 +239,14 @@ func New(
|
|||
m.Get(router.CompleteAbout).Handler(r.StaticHTML("landing/about.tmpl"))
|
||||
|
||||
var nh = noticeHandler{
|
||||
notices: ns,
|
||||
pinned: ps,
|
||||
notices: dbs.Notices,
|
||||
pinned: dbs.PinnedNotices,
|
||||
}
|
||||
m.Get(router.CompleteNoticeList).Handler(r.HTML("notice/list.tmpl", nh.list))
|
||||
m.Get(router.CompleteNoticeShow).Handler(r.HTML("notice/show.tmpl", nh.show))
|
||||
|
||||
var ih = inviteHandler{
|
||||
invites: is,
|
||||
invites: dbs.Invites,
|
||||
}
|
||||
m.Get(router.CompleteInviteAccept).Handler(r.HTML("invite/accept.tmpl", ih.acceptForm))
|
||||
m.Get(router.CompleteInviteConsume).Handler(r.HTML("invite/consumed.tmpl", ih.consume))
|
||||
|
@ -255,7 +264,7 @@ func New(
|
|||
// apply HTTP middleware
|
||||
middlewares := []func(http.Handler) http.Handler{
|
||||
logging.InjectHandler(logger),
|
||||
user.ContextInjecter(fs, a),
|
||||
user.ContextInjecter(dbs.AuthFallback, a),
|
||||
CSRF,
|
||||
}
|
||||
|
||||
|
@ -264,8 +273,8 @@ func New(
|
|||
}
|
||||
|
||||
var finalHandler http.Handler = mainMux
|
||||
for _, mw := range middlewares {
|
||||
finalHandler = mw(finalHandler)
|
||||
for _, applyMiddleware := range middlewares {
|
||||
finalHandler = applyMiddleware(finalHandler)
|
||||
}
|
||||
|
||||
return finalHandler, nil
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
"net/http"
|
||||
|
||||
"go.mindeco.de/http/render"
|
||||
"go.mindeco.de/logging"
|
||||
|
||||
"github.com/go-kit/kit/log/level"
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/admindb"
|
||||
weberrors "github.com/ssb-ngi-pointer/go-ssb-room/web/errors"
|
||||
|
@ -20,7 +22,9 @@ type inviteHandler struct {
|
|||
}
|
||||
|
||||
func (h inviteHandler) acceptForm(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
inv, err := h.invites.GetByToken(req.Context(), req.URL.Query().Get("token"))
|
||||
token := req.URL.Query().Get("token")
|
||||
|
||||
inv, err := h.invites.GetByToken(req.Context(), token)
|
||||
if err != nil {
|
||||
if errors.Is(err, admindb.ErrNotFound) {
|
||||
return nil, weberrors.ErrNotFound{What: "invite"}
|
||||
|
@ -29,7 +33,9 @@ func (h inviteHandler) acceptForm(rw http.ResponseWriter, req *http.Request) (in
|
|||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"Invite": inv,
|
||||
"Token": token,
|
||||
"Invite": inv,
|
||||
|
||||
csrf.TemplateTag: csrf.TemplateField(req),
|
||||
}, nil
|
||||
}
|
||||
|
@ -39,6 +45,8 @@ func (h inviteHandler) consume(rw http.ResponseWriter, req *http.Request) (inter
|
|||
return nil, weberrors.ErrBadRequest{Where: "form data", Details: err}
|
||||
}
|
||||
|
||||
alias := req.FormValue("alias")
|
||||
|
||||
token := req.FormValue("token")
|
||||
|
||||
newMember, err := refs.ParseFeedRef(req.FormValue("new_member"))
|
||||
|
@ -53,6 +61,15 @@ func (h inviteHandler) consume(rw http.ResponseWriter, req *http.Request) (inter
|
|||
}
|
||||
return nil, err
|
||||
}
|
||||
log := logging.FromContext(req.Context())
|
||||
level.Info(log).Log("event", "invite consumed", "id", inv.ID, "ref", newMember.ShortRef())
|
||||
|
||||
if alias != "" {
|
||||
level.Warn(log).Log(
|
||||
"TODO", "invite registration",
|
||||
"alias", alias,
|
||||
)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"TunnelAddress": "pew pew",
|
||||
|
|
|
@ -80,12 +80,14 @@ func setup(t *testing.T) *testSession {
|
|||
testRepo,
|
||||
"localhost",
|
||||
ts.RoomState,
|
||||
ts.AuthDB,
|
||||
ts.AuthFallbackDB,
|
||||
ts.AllowListDB,
|
||||
ts.InvitesDB,
|
||||
ts.NoticeDB,
|
||||
ts.PinnedDB,
|
||||
Databases{
|
||||
AuthWithSSB: ts.AuthDB,
|
||||
AuthFallback: ts.AuthFallbackDB,
|
||||
AllowList: ts.AllowListDB,
|
||||
Invites: ts.InvitesDB,
|
||||
Notices: ts.NoticeDB,
|
||||
PinnedNotices: ts.PinnedDB,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal("setup: handler init failed:", err)
|
||||
|
|
|
@ -2,6 +2,7 @@ GenericConfirm = "Yes"
|
|||
GenericGoBack = "Back"
|
||||
GenericSave = "Save"
|
||||
GenericPreview = "Preview"
|
||||
GenericLanguage = "Language"
|
||||
|
||||
PageNotFound = "The requested page was not found."
|
||||
|
||||
|
@ -45,9 +46,13 @@ NavAdminInvites = "Invites"
|
|||
NavAdminNotices = "Notices"
|
||||
|
||||
InviteAccept = "Accept invite"
|
||||
InviteAcceptTitle = "Accept Invite
|
||||
InviteAcceptTitle = "Accept Invite"
|
||||
InviteAcceptWelcome = "elaborate welcome message for a new member with good words and stuff."
|
||||
InviteAcceptAliasSuggestion = "The persone who created thought you might like this alias:"
|
||||
InviteAcceptPublicKey = "Public Key"
|
||||
|
||||
InviteConsumedTitle = "Invite accepted!"
|
||||
InviteConsumedWelcome = "Even more elaborate message that the person is now a member of the room!"
|
||||
|
||||
NoticeEditTitle = "Edit Notice"
|
||||
NoticeList = "Notices"
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
>{{.Notice.Content}}</textarea>
|
||||
|
||||
<div class="my-4 flex flex-row items-center justify-start">
|
||||
<label class="mr-2">Language</label>
|
||||
<label class="mr-2">{{i18n "GenericLanguage"}}</label>
|
||||
<input
|
||||
type="text"
|
||||
name="language"
|
||||
|
|
|
@ -1,16 +1,49 @@
|
|||
{{ define "title" }}{{i18n "InviteAcceptTitle"}}{{ end }}
|
||||
{{ define "title" }}{{ i18n "InviteAcceptTitle" }}{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="flex flex-col justify-center items-center h-64">
|
||||
|
||||
<span
|
||||
id="welcome"
|
||||
class="text-center"
|
||||
>{{i18n "InviteAcceptWelcome"}}</span>
|
||||
>{{ i18n "InviteAcceptWelcome" }}</span>
|
||||
|
||||
|
||||
{{if ne .AliasSuggestion ""}}
|
||||
<!-- https://github.com/ssb-ngi-pointer/go-ssb-room/issues/60 -->
|
||||
<p>{{i18n "InviteAcceptAliasSuggestion"}} {{.AliasSuggestion}}</p>
|
||||
{{end}}
|
||||
|
||||
|
||||
|
||||
<form id="confirm" action="{{urlTo "complete:invite:consume"}}" method="POST">
|
||||
{{ .csrfField }}
|
||||
<input type="hidden" name="token" value={{.Token}}>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
|
||||
<div class="my-4 flex flex-row items-center justify-start">
|
||||
<label class="mr-2">{{ i18n "InviteAcceptPublicKey" }}</label>
|
||||
<input
|
||||
type="text"
|
||||
name="new_member"
|
||||
placeholder="@ .ed25519"
|
||||
class="shadow rounded border border-transparent h-8 p-1 focus:outline-none focus:ring-2 focus:ring-pink-400 focus:border-transparent">
|
||||
<span class="ml-2 text-red-400">TODO: make this a dropdown</span>
|
||||
</div>
|
||||
|
||||
{{ if ne .Invite.AliasSuggestion "" }}
|
||||
<p>{{ i18n "InviteAcceptAliasSuggestion" }}</p>
|
||||
<input
|
||||
name="alias"
|
||||
value="{{ .Invite.AliasSuggestion }}"
|
||||
></p>
|
||||
{{ end }}
|
||||
|
||||
<a
|
||||
href="javascript:history.back()"
|
||||
class="px-4 h-8 shadow rounded flex flex-row justify-center items-center bg-white align-middle text-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-300 focus:ring-opacity-50"
|
||||
>{{i18n "GenericGoBack"}}</a>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="shadow rounded px-4 h-8 text-gray-100 bg-pink-600 hover:bg-pink-700 focus:outline-none focus:ring-2 focus:ring-pink-600 focus:ring-opacity-50"
|
||||
>{{i18n "GenericConfirm"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
{{ end }}
|
|
@ -13,7 +13,7 @@ type roomUserContextKeyType string
|
|||
|
||||
var roomUserContextKey roomUserContextKeyType = "ssb:room:httpcontext:user"
|
||||
|
||||
// FromContext returns the user or nil of it's not logged in
|
||||
// FromContext returns the user or nil if not logged in
|
||||
func FromContext(ctx context.Context) *admindb.User {
|
||||
v := ctx.Value(roomUserContextKey)
|
||||
|
||||
|
@ -25,11 +25,10 @@ func FromContext(ctx context.Context) *admindb.User {
|
|||
return user
|
||||
}
|
||||
|
||||
// ContextInjecter returns the middleware that injects the user value into the request context
|
||||
// ContextInjecter returns middleware for injecting a user id into the request context
|
||||
func ContextInjecter(fs admindb.AuthFallbackService, a *auth.Handler) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
v, err := a.AuthenticateRequest(req)
|
||||
if err != nil {
|
||||
next.ServeHTTP(w, req)
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// MiddlewareForTests gives us a way to inject _test users_. It should not be used in production.
|
||||
// This is exists here because we need to use roomUserContextKey which shouldn't be exported either.
|
||||
// This is part of testing.go because we need to use roomUserContextKey, which shouldn't be exported either.
|
||||
// TODO: could be protected with an extra build tag.
|
||||
// (Sadly +build test does not exist https://github.com/golang/go/issues/21360 )
|
||||
func MiddlewareForTests(user *admindb.User) func(http.Handler) http.Handler {
|
||||
|
|
Loading…
Reference in New Issue