~emersion/sinwon

3118ac0a8e2a42fb54ae102fba58559125e2848b — Simon Ser 7 months ago 03bad95
Add server name config directive

References: https://todo.sr.ht/~emersion/sinwon/24
M client.go => client.go +4 -6
@@ 46,13 46,12 @@ func manageClient(w http.ResponseWriter, req *http.Request) {

	if req.Method != http.MethodPost {
		data := struct {
			TemplateBaseData
			Client *Client
		}{
			Client: client,
		}
		if err := tpl.ExecuteTemplate(w, "manage-client.html", &data); err != nil {
			panic(err)
		}
		tpl.MustExecuteTemplate(w, "manage-client.html", &data)
		return
	}



@@ 107,15 106,14 @@ func manageClient(w http.ResponseWriter, req *http.Request) {
	}

	data := struct {
		TemplateBaseData
		ClientID     string
		ClientSecret string
	}{
		ClientID:     client.ClientID,
		ClientSecret: clientSecret,
	}
	if err := tpl.ExecuteTemplate(w, "client-secret.html", &data); err != nil {
		panic(err)
	}
	tpl.MustExecuteTemplate(w, "client-secret.html", &data)
}

func validateAllowedRedirectURIs(rawRedirectURIs string) error {

M config.go => config.go +3 -2
@@ 7,8 7,9 @@ import (
)

type Config struct {
	Listen   string `scfg:"listen"`
	Database string `scfg:"database"`
	Listen     string `scfg:"listen"`
	Database   string `scfg:"database"`
	ServerName string `scfg:"server-name"`
}

func loadConfig(filename string) (*Config, error) {

M config.in => config.in +1 -0
@@ 1,2 1,3 @@
listen localhost:8080
database /var/lib/sinwon/main.db
server-name sinwon

M main.go => main.go +10 -2
@@ 4,7 4,6 @@ import (
	"context"
	"embed"
	"flag"
	"html/template"
	"log"
	"net"
	"net/http"


@@ 46,7 45,16 @@ func main() {
		log.Fatalf("Failed to open DB: %v", err)
	}

	tpl := template.Must(template.ParseFS(templateFS, "template/*.html"))
	tplBaseData := &TemplateBaseData{
		ServerName: cfg.ServerName,
	}
	if tplBaseData.ServerName == "" {
		tplBaseData.ServerName = "sinwon"
	}
	tpl, err := loadTemplate(templateFS, "template/*.html", tplBaseData)
	if err != nil {
		log.Fatalf("Failed to load template: %v", err)
	}

	mux := chi.NewRouter()
	mux.Handle("/static/*", http.FileServer(http.FS(staticFS)))

M middleware.go => middleware.go +41 -3
@@ 4,6 4,8 @@ import (
	"context"
	"fmt"
	"html/template"
	"io"
	"io/fs"
	"mime"
	"net/http"
)


@@ 25,8 27,8 @@ func dbFromContext(ctx context.Context) *DB {
	return ctx.Value(contextKeyDB).(*DB)
}

func templateFromContext(ctx context.Context) *template.Template {
	return ctx.Value(contextKeyTemplate).(*template.Template)
func templateFromContext(ctx context.Context) *Template {
	return ctx.Value(contextKeyTemplate).(*Template)
}

func loginTokenFromContext(ctx context.Context) *AccessToken {


@@ 37,7 39,7 @@ func loginTokenFromContext(ctx context.Context) *AccessToken {
	return v.(*AccessToken)
}

func newBaseContext(db *DB, tpl *template.Template) context.Context {
func newBaseContext(db *DB, tpl *Template) context.Context {
	ctx := context.Background()
	ctx = context.WithValue(ctx, contextKeyDB, db)
	ctx = context.WithValue(ctx, contextKeyTemplate, tpl)


@@ 109,3 111,39 @@ func loginTokenMiddleware(next http.Handler) http.Handler {
		next.ServeHTTP(w, req)
	})
}

type TemplateBaseData struct {
	ServerName string
}

func (data *TemplateBaseData) Base() *TemplateBaseData {
	return data
}

type TemplateData interface {
	Base() *TemplateBaseData
}

type Template struct {
	tpl      *template.Template
	baseData *TemplateBaseData
}

func loadTemplate(fs fs.FS, pattern string, baseData *TemplateBaseData) (*Template, error) {
	tpl, err := template.ParseFS(fs, pattern)
	if err != nil {
		return nil, err
	}
	return &Template{tpl: tpl, baseData: baseData}, nil
}

func (tpl *Template) MustExecuteTemplate(w io.Writer, filename string, data TemplateData) {
	if data == nil {
		data = tpl.baseData
	} else {
		*data.Base() = *tpl.baseData
	}
	if err := tpl.tpl.ExecuteTemplate(w, filename, data); err != nil {
		panic(err)
	}
}

M oauth2.go => oauth2.go +2 -3
@@ 148,13 148,12 @@ func authorize(w http.ResponseWriter, req *http.Request) {
	}
	if _, ok := req.PostForm["authorize"]; !ok {
		data := struct {
			TemplateBaseData
			Client *Client
		}{
			Client: client,
		}
		if err := tpl.ExecuteTemplate(w, "authorize.html", data); err != nil {
			panic(err)
		}
		tpl.MustExecuteTemplate(w, "authorize.html", &data)
		return
	}


M template/authorize.html => template/authorize.html +2 -2
@@ 1,8 1,8 @@
{{ template "head.html" }}
{{ template "head.html" .Base }}

<main>

<h1>sinwon</h1>
<h1>{{ .ServerName }}</h1>

<p>
	Authorize

M template/client-secret.html => template/client-secret.html +2 -2
@@ 1,8 1,8 @@
{{ template "head.html" }}
{{ template "head.html" .Base }}

<main>

<h1>sinwon</h1>
<h1>{{ .ServerName }}</h1>

<p>
	<strong>Client ID</strong>: <code>{{ .ClientID }}</code><br>

M template/head.html => template/head.html +1 -1
@@ 2,7 2,7 @@
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>sinwon</title>
	<title>{{ .ServerName }}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <link rel="stylesheet" href="/static/style.css"/>
</head>

M template/index.html => template/index.html +2 -2
@@ 1,8 1,8 @@
{{ template "head.html" }}
{{ template "head.html" .Base }}

<main>

<h1>sinwon</h1>
<h1>{{ .ServerName }}</h1>

<p>Welcome, {{ .Me.Username }}!</p>


M template/login.html => template/login.html +2 -2
@@ 1,8 1,8 @@
{{ template "head.html" }}
{{ template "head.html" .Base }}

<main>

<h1>sinwon</h1>
<h1>{{ .ServerName }}</h1>

<form method="post" action="">
	Username: <input type="text" name="username" autocomplete="username"><br>

M template/manage-client.html => template/manage-client.html +2 -2
@@ 1,8 1,8 @@
{{ template "head.html" }}
{{ template "head.html" .Base }}

<main>

<h1>sinwon</h1>
<h1>{{ .ServerName }}</h1>

<form method="post" action="">
	{{ if .Client.ClientID }}

M template/manage-user.html => template/manage-user.html +2 -2
@@ 1,8 1,8 @@
{{ template "head.html" }}
{{ template "head.html" .Base }}

<main>

<h1>sinwon</h1>
<h1>{{ .ServerName }}</h1>

<form method="post" action="">
	Username: <input type="text" name="username" value="{{ .User.Username }}" required><br>

M user.go => user.go +6 -12
@@ 49,6 49,7 @@ func index(w http.ResponseWriter, req *http.Request) {
	}

	data := struct {
		TemplateBaseData
		Me                *User
		AuthorizedClients []AuthorizedClient
		Clients           []Client


@@ 59,9 60,7 @@ func index(w http.ResponseWriter, req *http.Request) {
		Clients:           clients,
		Users:             users,
	}
	if err := tpl.ExecuteTemplate(w, "index.html", &data); err != nil {
		panic(err)
	}
	tpl.MustExecuteTemplate(w, "index.html", &data)
}

func login(w http.ResponseWriter, req *http.Request) {


@@ 89,9 88,7 @@ func login(w http.ResponseWriter, req *http.Request) {
	username := req.PostFormValue("username")
	password := req.PostFormValue("password")
	if username == "" {
		if err := tpl.ExecuteTemplate(w, "login.html", nil); err != nil {
			panic(err)
		}
		tpl.MustExecuteTemplate(w, "login.html", nil)
		return
	}



@@ 106,9 103,7 @@ func login(w http.ResponseWriter, req *http.Request) {
	if err != nil {
		log.Printf("login failed for user %q: %v", username, err)
		// TODO: show error message
		if err := tpl.ExecuteTemplate(w, "login.html", nil); err != nil {
			panic(err)
		}
		tpl.MustExecuteTemplate(w, "login.html", nil)
		return
	}



@@ 186,15 181,14 @@ func manageUser(w http.ResponseWriter, req *http.Request) {
	admin := req.PostFormValue("admin") == "on"
	if username == "" {
		data := struct {
			TemplateBaseData
			User *User
			Me   *User
		}{
			User: user,
			Me:   me,
		}
		if err := tpl.ExecuteTemplate(w, "manage-user.html", &data); err != nil {
			panic(err)
		}
		tpl.MustExecuteTemplate(w, "manage-user.html", &data)
		return
	}