mirror of
https://git.ptzo.gdn/feditools/relay.git
synced 2024-09-21 09:47:11 +00:00
common login (#124)
This commit is contained in:
parent
3836bd0fb8
commit
448fda02a8
7
.github/workflows/pull-request.yml
vendored
7
.github/workflows/pull-request.yml
vendored
@ -24,12 +24,7 @@ jobs:
|
||||
go-version-file: 'go.mod'
|
||||
cache: true
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
with:
|
||||
args: build --rm-dist --snapshot
|
||||
args: build --rm-dist --snapshot --single-target
|
21
Makefile
21
Makefile
@ -16,6 +16,9 @@ clean:
|
||||
@rm -Rvf .cache coverage.txt dist relay
|
||||
@find . -name ".DS_Store" -exec rm -v {} \;
|
||||
|
||||
docker-pull:
|
||||
docker-compose --project-name ${PROJECT_NAME} -f deployments/docker-compose-test.yaml pull
|
||||
|
||||
docker-restart: docker-stop docker-start
|
||||
|
||||
docker-start:
|
||||
@ -31,26 +34,16 @@ fmt:
|
||||
i18n-extract:
|
||||
goi18n extract -format yaml -outdir web/locales -crowdin
|
||||
|
||||
i18n-merge:
|
||||
goi18n merge -format yaml -outdir locales web/locales/active.*.toml web/locales/translate.*.toml -crowdin
|
||||
|
||||
i18n-translations:
|
||||
goi18n merge -format yaml -outdir locales web/locales/active.*.toml -crowdin
|
||||
|
||||
lint:
|
||||
@echo linting
|
||||
@golint $(shell go list ./... | grep -v /vendor/)
|
||||
|
||||
release: clean
|
||||
goreleaser release
|
||||
|
||||
test: tidy fmt lint #gosec
|
||||
test: tidy fmt
|
||||
go test -cover ./...
|
||||
|
||||
test-ext: tidy fmt lint #gosec
|
||||
test-ext: tidy fmt
|
||||
go test --tags=postgres -cover ./...
|
||||
|
||||
test-bench-ext: tidy fmt lint #gosec
|
||||
test-bench-ext: tidy fmt
|
||||
go test -run=XXX -bench=. --tags=postgres -cover ./...
|
||||
|
||||
tidy:
|
||||
@ -59,4 +52,4 @@ tidy:
|
||||
vendor: tidy
|
||||
go mod vendor
|
||||
|
||||
.PHONY: build-snapshot bun-new-migration clean fmt i18n-extract i18n-merge i18n-translations lint stage-static npm-scss npm-upgrade docker-restart docker-start docker-stop release stage-static test test-ext test-race test-race-ext test-verbose tidy vendor
|
||||
.PHONY: build-snapshot bun-new-migration clean docker-pull docker-restart docker-start docker-stop fmt i18n-extract release stage-static test test-ext test-bench-ext tidy vendor
|
||||
|
@ -18,7 +18,7 @@ type Common struct {
|
||||
FooterExtraScript []string
|
||||
HeadLinks []libtemplate.HeadLink
|
||||
|
||||
NavBar Navbar
|
||||
NavBar libtemplate.Navbar
|
||||
NavBarDark bool
|
||||
PageTitle string
|
||||
}
|
||||
@ -58,7 +58,7 @@ func (t *Common) SetLocalizer(l *language.Localizer) {
|
||||
}
|
||||
|
||||
// SetNavbar sets the top level navbar used by the template.
|
||||
func (t *Common) SetNavbar(nodes Navbar) {
|
||||
func (t *Common) SetNavbar(nodes libtemplate.Navbar) {
|
||||
t.NavBar = nodes
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,54 @@
|
||||
package template
|
||||
|
||||
// LoginName is the name of the login template.
|
||||
const LoginName = "login"
|
||||
import (
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
)
|
||||
|
||||
// Login contains the variables for the "login" template.
|
||||
type Login struct {
|
||||
Common
|
||||
|
||||
FormError string
|
||||
FormInstance string
|
||||
libtemplate.Login
|
||||
}
|
||||
|
||||
// AddHeadLink adds a headder link to the template.
|
||||
func (t *Login) AddHeadLink(l libtemplate.HeadLink) {
|
||||
if t.HeadLinks == nil {
|
||||
t.HeadLinks = []libtemplate.HeadLink{}
|
||||
}
|
||||
t.HeadLinks = append(t.HeadLinks, l)
|
||||
}
|
||||
|
||||
// AddFooterScript adds a footer script to the template.
|
||||
func (t *Login) AddFooterScript(s libtemplate.Script) {
|
||||
if t.FooterScripts == nil {
|
||||
t.FooterScripts = []libtemplate.Script{}
|
||||
}
|
||||
t.FooterScripts = append(t.FooterScripts, s)
|
||||
}
|
||||
|
||||
// AddFooterExtraScript adds a footer script to the template.
|
||||
func (t *Login) AddFooterExtraScript(s string) {
|
||||
if t.FooterExtraScript == nil {
|
||||
t.FooterExtraScript = []string{}
|
||||
}
|
||||
t.FooterExtraScript = append(t.FooterExtraScript, s)
|
||||
}
|
||||
|
||||
// SetLanguage sets the template's default language.
|
||||
func (t *Login) SetLanguage(l string) {
|
||||
t.Language = l
|
||||
}
|
||||
|
||||
// SetLocalizer sets the localizer the template will use to generate text.
|
||||
func (t *Login) SetLocalizer(l *language.Localizer) {
|
||||
t.TextLogin = l.TextLogin()
|
||||
}
|
||||
|
||||
// SetNavbar sets the top level navbar used by the template.
|
||||
func (t *Login) SetNavbar(nodes libtemplate.Navbar) {}
|
||||
|
||||
// SetNavbarDark sets the navbar theme.
|
||||
func (t *Login) SetNavbarDark(dark bool) {}
|
||||
|
||||
// SetAccount sets the currently logged-in account.
|
||||
func (t *Login) SetAccount(account *models.Account) {}
|
||||
|
@ -1,11 +1,6 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
)
|
||||
|
||||
/*
|
||||
// Navbar is a navbar that can be added to a page.
|
||||
type Navbar []NavbarNode
|
||||
|
||||
@ -51,3 +46,4 @@ type NavbarNode struct {
|
||||
|
||||
Children Navbar
|
||||
}
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@ type InitTemplate interface {
|
||||
SetAccount(account *models.Account)
|
||||
SetLanguage(l string)
|
||||
SetLocalizer(l *language.Localizer)
|
||||
SetNavbar(nodes Navbar)
|
||||
SetNavbar(nodes libtemplate.Navbar)
|
||||
SetNavbarDark(dark bool)
|
||||
}
|
||||
|
||||
|
@ -2,50 +2,59 @@ package webapp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/db"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
nethttp "net/http"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// LoginGetHandler serves the login page.
|
||||
func (m *Module) LoginGetHandler(w nethttp.ResponseWriter, r *nethttp.Request) {
|
||||
m.displayLoginPage(w, r, "", "")
|
||||
func (m *Module) LoginGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
m.displayLoginPage(w, r, "", nil)
|
||||
}
|
||||
|
||||
// LoginPostHandler attempts a login.
|
||||
func (m *Module) LoginPostHandler(w nethttp.ResponseWriter, r *nethttp.Request) {
|
||||
func (m *Module) LoginPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
l := logger.WithField("func", "LoginPostHandler")
|
||||
|
||||
// parse form data
|
||||
if err := r.ParseForm(); err != nil {
|
||||
m.returnErrorPage(w, r, nethttp.StatusInternalServerError, err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// split account
|
||||
formInstance := r.Form.Get(FormInstance)
|
||||
domain := r.Form.Get(FormInstance)
|
||||
if domain == "" {
|
||||
m.displayLoginPage(w, r, "", &libtemplate.Alert{
|
||||
Color: libtemplate.ColorWarning,
|
||||
Text: "Please enter an instance domain.",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// get instance
|
||||
instance, err := m.db.ReadInstanceByDomain(r.Context(), formInstance)
|
||||
instance, err := m.db.ReadInstanceByDomain(r.Context(), domain)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
// actual db error
|
||||
m.returnErrorPage(w, r, nethttp.StatusInternalServerError, err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
if errors.Is(err, db.ErrNoEntries) {
|
||||
instance, err = m.fedi.GenInstanceFromDomain(r.Context(), formInstance)
|
||||
instance, err = m.fedi.GenInstanceFromDomain(r.Context(), domain)
|
||||
if err != nil {
|
||||
m.returnErrorPage(w, r, nethttp.StatusInternalServerError, err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = m.db.CreateInstance(r.Context(), instance)
|
||||
if err != nil {
|
||||
m.returnErrorPage(w, r, nethttp.StatusInternalServerError, err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
@ -55,28 +64,32 @@ func (m *Module) LoginPostHandler(w nethttp.ResponseWriter, r *nethttp.Request)
|
||||
loginURL, err := m.logic.GetLoginURL(r.Context(), instance)
|
||||
if err != nil {
|
||||
l.Errorf("get login url: %s", err.Error())
|
||||
m.returnErrorPage(w, r, nethttp.StatusInternalServerError, err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
nethttp.Redirect(w, r, loginURL.String(), nethttp.StatusFound)
|
||||
http.Redirect(w, r, loginURL.String(), http.StatusFound)
|
||||
}
|
||||
|
||||
func (m *Module) displayLoginPage(w nethttp.ResponseWriter, r *nethttp.Request, account, formError string) {
|
||||
// l := logger.WithField("func", "displayLoginPage")
|
||||
|
||||
func (m *Module) displayLoginPage(w http.ResponseWriter, r *http.Request, instance string, formError *libtemplate.Alert) {
|
||||
// get localizer
|
||||
localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) // nolint
|
||||
|
||||
// Init template variables
|
||||
tmplVars := &template.Login{}
|
||||
tmplVars := &template.Login{
|
||||
Login: libtemplate.Login{
|
||||
FormError: formError,
|
||||
FormInstance: libtemplate.FormInput{
|
||||
Type: libtemplate.FormInputTypeText,
|
||||
Name: FormInstance,
|
||||
Placeholder: localizer.TextInstance().String(),
|
||||
Value: instance,
|
||||
Required: true,
|
||||
},
|
||||
LogoHRef: m.logoSrcDark,
|
||||
},
|
||||
}
|
||||
|
||||
tmplVars.PageTitle = localizer.TextLogin().String()
|
||||
|
||||
// set form values
|
||||
tmplVars.FormError = formError
|
||||
tmplVars.FormInstance = account
|
||||
|
||||
m.executeTemplate(w, r, template.LoginName, tmplVars)
|
||||
m.executeTemplate(w, r, libtemplate.LoginName, tmplVars)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package webapp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
@ -89,7 +90,7 @@ func (m *Module) initTemplate(_ http.ResponseWriter, r *http.Request, tmpl templ
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
func (m *Module) makeNavbar(r *http.Request) (libtemplate.Navbar, error) {
|
||||
tctx, span := m.tracer.Start(r.Context(), "makeNavbar", m.tracerAttrs...)
|
||||
defer span.End()
|
||||
|
||||
@ -99,11 +100,11 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
l := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) // nolint
|
||||
|
||||
// create navbar
|
||||
newNavbar := template.Navbar{
|
||||
newNavbar := libtemplate.Navbar{
|
||||
{
|
||||
Text: l.TextHomeWeb().String(),
|
||||
MatchStr: path.ReAppHome,
|
||||
FAIcon: "house",
|
||||
Icon: "house",
|
||||
URL: path.AppHome,
|
||||
},
|
||||
}
|
||||
@ -116,10 +117,10 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
return nil, err
|
||||
}
|
||||
if blockCount > 0 {
|
||||
newNode := template.NavbarNode{
|
||||
newNode := libtemplate.NavbarNode{
|
||||
Text: l.TextBlocks().String(),
|
||||
MatchStr: path.ReAppBlocks,
|
||||
FAIcon: "user-slash",
|
||||
Icon: "user-slash",
|
||||
URL: path.AppBlocks,
|
||||
}
|
||||
newNavbar = append(newNavbar, newNode)
|
||||
@ -130,34 +131,34 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
|
||||
if loggedIn {
|
||||
if account.ContactFor != nil {
|
||||
newNavbar = append(newNavbar, template.NavbarNode{
|
||||
newNavbar = append(newNavbar, libtemplate.NavbarNode{
|
||||
Text: l.TextInstance().String(),
|
||||
MatchStr: path.ReAppInstance,
|
||||
FAIcon: "server",
|
||||
Icon: "server",
|
||||
URL: path.AppInstance,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
newNavbar = append(newNavbar, template.NavbarNode{
|
||||
newNavbar = append(newNavbar, libtemplate.NavbarNode{
|
||||
Text: l.TextSettings().String(),
|
||||
MatchStr: path.ReAppSettings,
|
||||
FAIcon: "gear",
|
||||
Icon: "gear",
|
||||
URL: path.AppSettings,
|
||||
})
|
||||
|
||||
if account.IsAdmin || account.IsMod {
|
||||
newNode := template.NavbarNode{
|
||||
newNode := libtemplate.NavbarNode{
|
||||
Text: l.TextAdmin().String(),
|
||||
MatchStr: path.ReAppAdminPre,
|
||||
FAIcon: "screwdriver-wrench",
|
||||
Icon: "screwdriver-wrench",
|
||||
URL: path.AppAdminHome,
|
||||
|
||||
Children: template.Navbar{
|
||||
Children: libtemplate.Navbar{
|
||||
{
|
||||
Text: l.TextConfiguration().String(),
|
||||
MatchStr: path.ReAppAdminHome,
|
||||
FAIcon: "gear",
|
||||
Icon: "gear",
|
||||
URL: path.AppAdminHome,
|
||||
},
|
||||
{
|
||||
@ -166,19 +167,19 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
{
|
||||
Text: l.TextAccounts().String(),
|
||||
MatchStr: path.ReAppAdminAccountPre,
|
||||
FAIcon: "user",
|
||||
Icon: "user",
|
||||
URL: path.AppAdminAccount,
|
||||
},
|
||||
{
|
||||
Text: l.TextBlocks().String(),
|
||||
MatchStr: path.ReAppAdminBlockPre,
|
||||
FAIcon: "user-slash",
|
||||
Icon: "user-slash",
|
||||
URL: path.AppAdminBlock,
|
||||
},
|
||||
{
|
||||
Text: l.TextInstances().String(),
|
||||
MatchStr: path.ReAppAdminInstancesPre,
|
||||
FAIcon: "server",
|
||||
Icon: "server",
|
||||
URL: path.AppAdminInstance,
|
||||
},
|
||||
{
|
||||
@ -187,13 +188,13 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
{
|
||||
Text: l.TextJobs().String(),
|
||||
MatchStr: path.ReAppAdminJobPre,
|
||||
FAIcon: "person-running",
|
||||
Icon: "person-running",
|
||||
URL: path.AppAdminJob,
|
||||
},
|
||||
{
|
||||
Text: l.TextStatistics().String(),
|
||||
MatchStr: path.ReAppAdminStatisticsPre,
|
||||
FAIcon: "chart-line",
|
||||
Icon: "chart-line",
|
||||
URL: path.AppAdminStatistics,
|
||||
},
|
||||
},
|
||||
|
@ -51,8 +51,9 @@ type Module struct {
|
||||
footerScriptChartJS libtemplate.Script
|
||||
}
|
||||
|
||||
//revive:disable:argument-limit
|
||||
// New returns a new webapp module.
|
||||
//
|
||||
//revive:disable:argument-limit
|
||||
func New(
|
||||
ctx context.Context,
|
||||
d db.DB,
|
||||
|
@ -88,18 +88,6 @@ db-crypto-key: "test1234test5678test9123test4567"
|
||||
# Default: ""
|
||||
redis-password: "test"
|
||||
|
||||
#############
|
||||
## METRICS ##
|
||||
#############
|
||||
|
||||
# String. Address and port of the statsd instance
|
||||
# Default: "localhost:8125"
|
||||
#statsd-addr: "localhost:8125"
|
||||
|
||||
# String. Prefix to add to statsd metrics
|
||||
# Default: "democrablock"
|
||||
#statsd-prefix: ""
|
||||
|
||||
#######
|
||||
# WEB #
|
||||
#######
|
||||
|
@ -1,58 +0,0 @@
|
||||
{{ define "login" -}}
|
||||
<!doctype html>
|
||||
<html lang="{{ .Language }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>{{ .PageTitle }}</title>
|
||||
{{ range $link := .HeadLinks }}
|
||||
{{template "head_link" $link -}}
|
||||
{{- end }}
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.centerbox {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.centerbox .form-control {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-center">
|
||||
<div class="centerbox" style="max-width: 330px">
|
||||
<form method="post">
|
||||
<img class="mb-4" src="{{ logoSrcDark }}" alt="" width="100" height="100">
|
||||
<h1 class="h3 mb-3 font-weight-normal">{{ .Localizer.TextLogin }}</h1>
|
||||
{{- if .FormError }}
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
{{.FormError}}
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{{- end }}
|
||||
<input class="form-control" type="text" name="instance" {{if .FormInstance}}value="{{.FormInstance}}" {{end}}placeholder="{{ .Localizer.TextInstance }}" aria-label="instance">
|
||||
<button type="submit" class="btn btn-lg btn-primary btn-block">{{ .Localizer.TextLogin }}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{- range $link := .FooterScripts}}
|
||||
{{template "script" $link }}
|
||||
{{- end}}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
@ -18,7 +18,7 @@
|
||||
{{- if .Children }}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle{{if .Active}} active{{end}}{{if .Disabled}} disabled{{end}}" href="{{.URL}}" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{{if .FAIcon}}<i class="fas fa-{{.FAIcon}}"></i> {{end}}{{.Text}}
|
||||
{{if .Icon}}<i class="fas fa-{{.Icon}}"></i> {{end}}{{.Text}}
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
|
||||
{{- range .Children}}
|
||||
@ -27,7 +27,7 @@
|
||||
{{- else }}
|
||||
<li class="nav-item">
|
||||
<a class="dropdown-item{{if .Active}} active{{end}}{{if .Disabled}} disabled{{end}}" href="{{.URL}}">
|
||||
{{if .FAIcon}}<i class="fas fa-{{.FAIcon}}"></i> {{end}}{{.Text}}
|
||||
{{if .Icon}}<i class="fas fa-{{.Icon}}"></i> {{end}}{{.Text}}
|
||||
</a>
|
||||
</li>
|
||||
{{- end }}
|
||||
@ -37,7 +37,7 @@
|
||||
{{- else}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{{if .Active}} active{{end}}{{if .Disabled}} disabled{{end}}"{{if .Active}} aria-current="page"{{end}} href="{{.URL}}">
|
||||
{{if .FAIcon}}<i class="fas fa-{{.FAIcon}}"></i> {{end}}{{.Text}}
|
||||
{{if .Icon}}<i class="fas fa-{{.Icon}}"></i> {{end}}{{.Text}}
|
||||
</a>
|
||||
</li>
|
||||
{{- end -}}
|
||||
|
@ -3,6 +3,7 @@ package web
|
||||
import "embed"
|
||||
|
||||
// Files contains static files required by the application
|
||||
//
|
||||
//go:embed locales/active.*.yaml
|
||||
//go:embed template/*
|
||||
var Files embed.FS
|
||||
|
Loading…
Reference in New Issue
Block a user