Merge pull request #20 from Haelnorr/development

General fixes and minor updates
This commit is contained in:
2025-02-22 20:35:12 +11:00
committed by GitHub
26 changed files with 142 additions and 312 deletions

View File

@@ -33,11 +33,15 @@ jobs:
- name: Build the binary - name: Build the binary
run: make build SUFFIX=-production-$GITHUB_SHA run: make build SUFFIX=-production-$GITHUB_SHA
- name: Build the migration binary
run: make migrate SUFFIX=-production-$GITHUB_SHA
- name: Deploy to Server - name: Deploy to Server
env: env:
USER: deploy USER: deploy
HOST: projectreshoot.com HOST: projectreshoot.com
DIR: /home/deploy/releases/production DIR: /home/deploy/releases/production
MIG_DIR: /home/deploy/migration-bin
DEPLOY_SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }} DEPLOY_SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
run: | run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -49,7 +53,13 @@ jobs:
echo " UserKnownHostsFile /dev/null" >> ~/.ssh/config echo " UserKnownHostsFile /dev/null" >> ~/.ssh/config
ssh -i ~/.ssh/id_ed25519 $USER@$HOST mkdir -p $DIR ssh -i ~/.ssh/id_ed25519 $USER@$HOST mkdir -p $DIR
scp -i ~/.ssh/id_ed25519 projectreshoot-production-${GITHUB_SHA} $USER@$HOST:$DIR scp -i ~/.ssh/id_ed25519 projectreshoot-production-${GITHUB_SHA} $USER@$HOST:$DIR
ssh -i ~/.ssh/id_ed25519 $USER@$HOST 'bash -s' < ./deploy/deploy_production.sh $GITHUB_SHA ssh -i ~/.ssh/id_ed25519 $USER@$HOST mkdir -p $MIG_DIR
scp -i ~/.ssh/id_ed25519 prmigrate-production-${GITHUB_SHA} $USER@$HOST:$MIG_DIR
scp -i ~/.ssh/id_ed25519 ./deploy/db/backup.sh $USER@$HOST:$MIG_DIR
scp -i ~/.ssh/id_ed25519 ./deploy/db/migrate.sh $USER@$HOST:$MIG_DIR
scp -i ~/.ssh/id_ed25519 ./deploy/db/migrationcleanup.sh $USER@$HOST:$MIG_DIR
ssh -i ~/.ssh/id_ed25519 $USER@$HOST 'bash -s' < ./deploy/deploy.sh $GITHUB_SHA production

View File

@@ -56,11 +56,12 @@ func fetchUserData(
return rows, nil return rows, nil
} }
// Scan the next row into the provided user pointer. Calls rows.Next() and // Calls rows.Next() and scans the row into the provided user pointer.
// assumes only row in the result. Providing a rows object with more than 1 // Will error if no row available
// row may result in undefined behaviour.
func scanUserRow(user *User, rows *sql.Rows) error { func scanUserRow(user *User, rows *sql.Rows) error {
for rows.Next() { if !rows.Next() {
return errors.New("User not found")
}
err := rows.Scan( err := rows.Scan(
&user.ID, &user.ID,
&user.Username, &user.Username,
@@ -71,7 +72,6 @@ func scanUserRow(user *User, rows *sql.Rows) error {
if err != nil { if err != nil {
return errors.Wrap(err, "rows.Scan") return errors.Wrap(err, "rows.Scan")
} }
}
return nil return nil
} }

View File

@@ -1,12 +1,58 @@
projectreshoot.com { projectreshoot.com {
rate_limit {
zone auth {
match {
method POST
path /login /register
}
key {remote_host}
events 4
window 1m
}
zone client {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:3000 localhost:3001 localhost:3002 { reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
transport http {
max_conns_per_host 10
}
health_uri /healthz health_uri /healthz
fail_duration 30s fail_duration 30s
} }
log {
output file /var/log/caddy/access.log
}
} }
staging.projectreshoot.com { staging.projectreshoot.com {
rate_limit {
zone auth {
match {
method POST
path /login /register
}
key {remote_host}
events 4
window 1m
}
zone client {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:3005 localhost:3006 localhost:3007 { reverse_proxy localhost:3005 localhost:3006 localhost:3007 {
transport http {
max_conns_per_host 10
}
health_uri /healthz health_uri /healthz
fail_duration 30s fail_duration 30s
} }
log {
output file /var/log/caddy/access-staging.log
}
} }

View File

@@ -1,94 +0,0 @@
#!/bin/bash
# Exit on error
set -e
# Check if commit hash is passed as an argument
if [ -z "$1" ]; then
echo "Usage: $0 <commit-hash>"
exit 1
fi
COMMIT_HASH=$1
RELEASES_DIR="/home/deploy/releases/production"
DEPLOY_BIN="/home/deploy/production/projectreshoot"
SERVICE_NAME="projectreshoot"
BINARY_NAME="projectreshoot-production-${COMMIT_HASH}"
declare -a PORTS=("3000" "3001" "3002")
# Check if the binary exists
if [ ! -f "${RELEASES_DIR}/${BINARY_NAME}" ]; then
echo "Binary ${BINARY_NAME} not found in ${RELEASES_DIR}"
exit 1
fi
# Keep a reference to the previous binary from the symlink
if [ -L "${DEPLOY_BIN}" ]; then
PREVIOUS=$(readlink -f $DEPLOY_BIN)
echo "Current binary is ${PREVIOUS}, saved for rollback."
else
echo "No symbolic link found, no previous binary to backup."
PREVIOUS=""
fi
rollback_deployment() {
if [ -n "$PREVIOUS" ]; then
echo "Rolling back to previous binary: ${PREVIOUS}"
ln -sfn "${PREVIOUS}" "${DEPLOY_BIN}"
else
echo "No previous binary to roll back to."
fi
# wait to restart the services
sleep 10
# Restart all services with the previous binary
for port in "${PORTS[@]}"; do
SERVICE="${SERVICE_NAME}@${port}.service"
echo "Restarting $SERVICE..."
sudo systemctl restart $SERVICE
done
echo "Rollback completed."
}
# Copy the binary to the deployment directory
echo "Promoting ${BINARY_NAME} to ${DEPLOY_BIN}..."
ln -sf "${RELEASES_DIR}/${BINARY_NAME}" "${DEPLOY_BIN}"
WAIT_TIME=5
restart_service() {
local port=$1
local SERVICE="${SERVICE_NAME}@${port}.service"
echo "Restarting ${SERVICE}..."
# Restart the service
if ! sudo systemctl restart "$SERVICE"; then
echo "Error: Failed to restart ${SERVICE}. Rolling back deployment."
# Call the rollback function
rollback_deployment
exit 1
fi
# Wait a few seconds to allow the service to fully start
echo "Waiting for ${SERVICE} to fully start..."
sleep $WAIT_TIME
# Check the status of the service
if ! systemctl is-active --quiet "${SERVICE}"; then
echo "Error: ${SERVICE} failed to start correctly. Rolling back deployment."
# Call the rollback function
rollback_deployment
exit 1
fi
echo "${SERVICE}.service restarted successfully."
}
for port in "${PORTS[@]}"; do
restart_service $port
done
echo "Deployment completed successfully."

View File

@@ -1,94 +0,0 @@
#!/bin/bash
# Exit on error
set -e
# Check if commit hash is passed as an argument
if [ -z "$1" ]; then
echo "Usage: $0 <commit-hash>"
exit 1
fi
COMMIT_HASH=$1
RELEASES_DIR="/home/deploy/releases/staging"
DEPLOY_BIN="/home/deploy/staging/projectreshoot"
SERVICE_NAME="staging.projectreshoot"
BINARY_NAME="projectreshoot-staging-${COMMIT_HASH}"
declare -a PORTS=("3005" "3006" "3007")
# Check if the binary exists
if [ ! -f "${RELEASES_DIR}/${BINARY_NAME}" ]; then
echo "Binary ${BINARY_NAME} not found in ${RELEASES_DIR}"
exit 1
fi
# Keep a reference to the previous binary from the symlink
if [ -L "${DEPLOY_BIN}" ]; then
PREVIOUS=$(readlink -f $DEPLOY_BIN)
echo "Current binary is ${PREVIOUS}, saved for rollback."
else
echo "No symbolic link found, no previous binary to backup."
PREVIOUS=""
fi
rollback_deployment() {
if [ -n "$PREVIOUS" ]; then
echo "Rolling back to previous binary: ${PREVIOUS}"
ln -sfn "${PREVIOUS}" "${DEPLOY_BIN}"
else
echo "No previous binary to roll back to."
fi
# wait to restart the services
sleep 10
# Restart all services with the previous binary
for port in "${PORTS[@]}"; do
SERVICE="${SERVICE_NAME}@${port}.service"
echo "Restarting $SERVICE..."
sudo systemctl restart $SERVICE
done
echo "Rollback completed."
}
# Copy the binary to the deployment directory
echo "Promoting ${BINARY_NAME} to ${DEPLOY_BIN}..."
ln -sf "${RELEASES_DIR}/${BINARY_NAME}" "${DEPLOY_BIN}"
WAIT_TIME=5
restart_service() {
local port=$1
local SERVICE="${SERVICE_NAME}@${port}.service"
echo "Restarting ${SERVICE}..."
# Restart the service
if ! sudo systemctl restart "$SERVICE"; then
echo "Error: Failed to restart ${SERVICE}. Rolling back deployment."
# Call the rollback function
rollback_deployment
exit 1
fi
# Wait a few seconds to allow the service to fully start
echo "Waiting for ${SERVICE} to fully start..."
sleep $WAIT_TIME
# Check the status of the service
if ! systemctl is-active --quiet "${SERVICE}"; then
echo "Error: ${SERVICE} failed to start correctly. Rolling back deployment."
# Call the rollback function
rollback_deployment
exit 1
fi
echo "${SERVICE}.service restarted successfully."
}
for port in "${PORTS[@]}"; do
restart_service $port
done
echo "Deployment completed successfully."

2
go.mod
View File

@@ -1,6 +1,6 @@
module projectreshoot module projectreshoot
go 1.23.5 go 1.24.0
require ( require (
github.com/a-h/templ v0.3.833 github.com/a-h/templ v0.3.833

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"context" "context"
@@ -16,7 +16,7 @@ import (
) )
// Renders the account page on the 'General' subpage // Renders the account page on the 'General' subpage
func HandleAccountPage() http.Handler { func AccountPage() http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("subpage") cookie, err := r.Cookie("subpage")
@@ -30,7 +30,7 @@ func HandleAccountPage() http.Handler {
} }
// Handles a request to change the subpage for the Accou/accountnt page // Handles a request to change the subpage for the Accou/accountnt page
func HandleAccountSubpage() http.Handler { func AccountSubpage() http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
r.ParseForm() r.ParseForm()
@@ -42,7 +42,7 @@ func HandleAccountSubpage() http.Handler {
} }
// Handles a request to change the users username // Handles a request to change the users username
func HandleChangeUsername( func ChangeUsername(
logger *zerolog.Logger, logger *zerolog.Logger,
conn *db.SafeConn, conn *db.SafeConn,
) http.Handler { ) http.Handler {
@@ -88,7 +88,7 @@ func HandleChangeUsername(
} }
// Handles a request to change the users bio // Handles a request to change the users bio
func HandleChangeBio( func ChangeBio(
logger *zerolog.Logger, logger *zerolog.Logger,
conn *db.SafeConn, conn *db.SafeConn,
) http.Handler { ) http.Handler {
@@ -144,7 +144,7 @@ func validateChangePassword(
} }
// Handles a request to change the users password // Handles a request to change the users password
func HandleChangePassword( func ChangePassword(
logger *zerolog.Logger, logger *zerolog.Logger,
conn *db.SafeConn, conn *db.SafeConn,
) http.Handler { ) http.Handler {

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"net/http" "net/http"

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"net/http" "net/http"
@@ -8,7 +8,7 @@ import (
// Handles responses to the / path. Also serves a 404 Page for paths that // Handles responses to the / path. Also serves a 404 Page for paths that
// don't have explicit handlers // don't have explicit handlers
func HandleRoot() http.Handler { func Root() http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" { if r.URL.Path != "/" {

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"context" "context"
@@ -49,7 +49,7 @@ func checkRememberMe(r *http.Request) bool {
// Handles an attempted login request. On success will return a HTMX redirect // Handles an attempted login request. On success will return a HTMX redirect
// and on fail will return the login form again, passing the error to the // and on fail will return the login form again, passing the error to the
// template for user feedback // template for user feedback
func HandleLoginRequest( func LoginRequest(
config *config.Config, config *config.Config,
logger *zerolog.Logger, logger *zerolog.Logger,
conn *db.SafeConn, conn *db.SafeConn,
@@ -97,7 +97,7 @@ func HandleLoginRequest(
// Handles a request to view the login page. Will attempt to set "pagefrom" // Handles a request to view the login page. Will attempt to set "pagefrom"
// cookie so a successful login can redirect the user to the page they came // cookie so a successful login can redirect the user to the page they came
func HandleLoginPage(trustedHost string) http.Handler { func LoginPage(trustedHost string) http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
cookies.SetPageFrom(w, r, trustedHost) cookies.SetPageFrom(w, r, trustedHost)

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"context" "context"
@@ -80,7 +80,7 @@ func revokeTokens(
} }
// Handle a logout request // Handle a logout request
func HandleLogout( func Logout(
config *config.Config, config *config.Config,
logger *zerolog.Logger, logger *zerolog.Logger,
conn *db.SafeConn, conn *db.SafeConn,

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"net/http" "net/http"

View File

@@ -1,11 +1,11 @@
package handlers package handler
import ( import (
"net/http" "net/http"
"projectreshoot/view/page" "projectreshoot/view/page"
) )
func HandleProfilePage() http.Handler { func ProfilePage() http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
page.Profile().Render(r.Context(), w) page.Profile().Render(r.Context(), w)

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"context" "context"
@@ -99,7 +99,7 @@ func validatePassword(
} }
// Handle request to reauthenticate (i.e. make token fresh again) // Handle request to reauthenticate (i.e. make token fresh again)
func HandleReauthenticate( func Reauthenticate(
logger *zerolog.Logger, logger *zerolog.Logger,
config *config.Config, config *config.Config,
conn *db.SafeConn, conn *db.SafeConn,

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"context" "context"
@@ -44,7 +44,7 @@ func validateRegistration(
return user, nil return user, nil
} }
func HandleRegisterRequest( func RegisterRequest(
config *config.Config, config *config.Config,
logger *zerolog.Logger, logger *zerolog.Logger,
conn *db.SafeConn, conn *db.SafeConn,
@@ -93,7 +93,7 @@ func HandleRegisterRequest(
// Handles a request to view the login page. Will attempt to set "pagefrom" // Handles a request to view the login page. Will attempt to set "pagefrom"
// cookie so a successful login can redirect the user to the page they came // cookie so a successful login can redirect the user to the page they came
func HandleRegisterPage(trustedHost string) http.Handler { func RegisterPage(trustedHost string) http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
cookies.SetPageFrom(w, r, trustedHost) cookies.SetPageFrom(w, r, trustedHost)

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"net/http" "net/http"
@@ -42,7 +42,7 @@ func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
// Handles requests for static files, without allowing access to the // Handles requests for static files, without allowing access to the
// directory viewer and returning 404 if an exact file is not found // directory viewer and returning 404 if an exact file is not found
func HandleStatic(staticFS *http.FileSystem) http.Handler { func StaticFS(staticFS *http.FileSystem) http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
nfs := justFilesFilesystem{*staticFS} nfs := justFilesFilesystem{*staticFS}

View File

@@ -1,4 +1,4 @@
package handlers package handler
import ( import (
"context" "context"

View File

@@ -10,7 +10,7 @@ import (
"projectreshoot/contexts" "projectreshoot/contexts"
"projectreshoot/cookies" "projectreshoot/cookies"
"projectreshoot/db" "projectreshoot/db"
"projectreshoot/handlers" "projectreshoot/handler"
"projectreshoot/jwt" "projectreshoot/jwt"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -119,7 +119,7 @@ func Authentication(
// Failed to start transaction, skip auth // Failed to start transaction, skip auth
logger.Warn().Err(err). logger.Warn().Err(err).
Msg("Skipping Auth - unable to start a transaction") Msg("Skipping Auth - unable to start a transaction")
handlers.ErrorPage(http.StatusServiceUnavailable, w, r) handler.ErrorPage(http.StatusServiceUnavailable, w, r)
return return
} }
user, err := getAuthenticatedUser(config, ctx, tx, w, r) user, err := getAuthenticatedUser(config, ctx, tx, w, r)

View File

@@ -3,7 +3,7 @@ package middleware
import ( import (
"net/http" "net/http"
"projectreshoot/contexts" "projectreshoot/contexts"
"projectreshoot/handlers" "projectreshoot/handler"
"time" "time"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@@ -31,7 +31,7 @@ func Logging(logger *zerolog.Logger, next http.Handler) http.Handler {
} }
start, err := contexts.GetStartTime(r.Context()) start, err := contexts.GetStartTime(r.Context())
if err != nil { if err != nil {
handlers.ErrorPage(http.StatusInternalServerError, w, r) handler.ErrorPage(http.StatusInternalServerError, w, r)
return return
} }
wrapped := &wrappedWriter{ wrapped := &wrappedWriter{
@@ -44,7 +44,7 @@ func Logging(logger *zerolog.Logger, next http.Handler) http.Handler {
Str("method", r.Method). Str("method", r.Method).
Str("resource", r.URL.Path). Str("resource", r.URL.Path).
Dur("time_elapsed", time.Since(start)). Dur("time_elapsed", time.Since(start)).
Str("remote_addr", r.RemoteAddr). Str("remote_addr", r.Header.Get("X-Forwarded-For")).
Msg("Served") Msg("Served")
}) })
} }

View File

@@ -3,15 +3,15 @@ package middleware
import ( import (
"net/http" "net/http"
"projectreshoot/contexts" "projectreshoot/contexts"
"projectreshoot/handlers" "projectreshoot/handler"
) )
// Checks if the user is set in the context and shows 401 page if not logged in // Checks if the user is set in the context and shows 401 page if not logged in
func RequiresLogin(next http.Handler) http.Handler { func LoginReq(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := contexts.GetUser(r.Context()) user := contexts.GetUser(r.Context())
if user == nil { if user == nil {
handlers.ErrorPage(http.StatusUnauthorized, w, r) handler.ErrorPage(http.StatusUnauthorized, w, r)
return return
} }
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
@@ -20,7 +20,7 @@ func RequiresLogin(next http.Handler) http.Handler {
// Checks if the user is set in the context and redirects them to profile if // Checks if the user is set in the context and redirects them to profile if
// they are logged in // they are logged in
func RequiresLogout(next http.Handler) http.Handler { func LogoutReq(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := contexts.GetUser(r.Context()) user := contexts.GetUser(r.Context())
if user != nil { if user != nil {

View File

@@ -33,7 +33,7 @@ func TestPageLoginRequired(t *testing.T) {
var maint uint32 var maint uint32
atomic.StoreUint32(&maint, 0) atomic.StoreUint32(&maint, 0)
// Add the middleware and create the server // Add the middleware and create the server
loginRequiredHandler := RequiresLogin(testHandler) loginRequiredHandler := LoginReq(testHandler)
authHandler := Authentication(logger, cfg, sconn, loginRequiredHandler, &maint) authHandler := Authentication(logger, cfg, sconn, loginRequiredHandler, &maint)
server := httptest.NewServer(authHandler) server := httptest.NewServer(authHandler)
defer server.Close() defer server.Close()

View File

@@ -6,7 +6,7 @@ import (
"time" "time"
) )
func RequiresFresh( func FreshReq(
next http.Handler, next http.Handler,
) http.Handler { ) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@@ -33,8 +33,8 @@ func TestReauthRequired(t *testing.T) {
var maint uint32 var maint uint32
atomic.StoreUint32(&maint, 0) atomic.StoreUint32(&maint, 0)
// Add the middleware and create the server // Add the middleware and create the server
reauthRequiredHandler := RequiresFresh(testHandler) reauthRequiredHandler := FreshReq(testHandler)
loginRequiredHandler := RequiresLogin(reauthRequiredHandler) loginRequiredHandler := LoginReq(reauthRequiredHandler)
authHandler := Authentication(logger, cfg, sconn, loginRequiredHandler, &maint) authHandler := Authentication(logger, cfg, sconn, loginRequiredHandler, &maint)
server := httptest.NewServer(authHandler) server := httptest.NewServer(authHandler)
defer server.Close() defer server.Close()

View File

@@ -5,7 +5,7 @@ import (
"projectreshoot/config" "projectreshoot/config"
"projectreshoot/db" "projectreshoot/db"
"projectreshoot/handlers" "projectreshoot/handler"
"projectreshoot/middleware" "projectreshoot/middleware"
"projectreshoot/view/page" "projectreshoot/view/page"
@@ -20,82 +20,44 @@ func addRoutes(
conn *db.SafeConn, conn *db.SafeConn,
staticFS *http.FileSystem, staticFS *http.FileSystem,
) { ) {
route := mux.Handle
loggedIn := middleware.LoginReq
loggedOut := middleware.LogoutReq
fresh := middleware.FreshReq
// Health check // Health check
mux.HandleFunc("GET /healthz", func(http.ResponseWriter, *http.Request) {}) mux.HandleFunc("GET /healthz", func(http.ResponseWriter, *http.Request) {})
// Static files // Static files
mux.Handle("GET /static/", http.StripPrefix("/static/", handlers.HandleStatic(staticFS))) route("GET /static/", http.StripPrefix("/static/", handler.StaticFS(staticFS)))
// Index page and unhandled catchall (404) // Index page and unhandled catchall (404)
mux.Handle("GET /", handlers.HandleRoot()) route("GET /", handler.Root())
// Static content, unprotected pages // Static content, unprotected pages
mux.Handle("GET /about", handlers.HandlePage(page.About())) route("GET /about", handler.HandlePage(page.About()))
// Login page and handlers // Login page and handlers
mux.Handle("GET /login", route("GET /login", loggedOut(handler.LoginPage(config.TrustedHost)))
middleware.RequiresLogout( route("POST /login", loggedOut(handler.LoginRequest(config, logger, conn)))
handlers.HandleLoginPage(config.TrustedHost),
))
mux.Handle("POST /login",
middleware.RequiresLogout(
handlers.HandleLoginRequest(
config,
logger,
conn,
)))
// Register page and handlers // Register page and handlers
mux.Handle("GET /register", route("GET /register", loggedOut(handler.RegisterPage(config.TrustedHost)))
middleware.RequiresLogout( route("POST /register", loggedOut(handler.RegisterRequest(config, logger, conn)))
handlers.HandleRegisterPage(config.TrustedHost),
))
mux.Handle("POST /register",
middleware.RequiresLogout(
handlers.HandleRegisterRequest(
config,
logger,
conn,
)))
// Logout // Logout
mux.Handle("POST /logout", handlers.HandleLogout(config, logger, conn)) route("POST /logout", handler.Logout(config, logger, conn))
// Reauthentication request // Reauthentication request
mux.Handle("POST /reauthenticate", route("POST /reauthenticate", loggedIn(handler.Reauthenticate(logger, config, conn)))
middleware.RequiresLogin(
handlers.HandleReauthenticate(logger, config, conn),
))
// Profile page // Profile page
mux.Handle("GET /profile", route("GET /profile", loggedIn(handler.ProfilePage()))
middleware.RequiresLogin(
handlers.HandleProfilePage(),
))
// Account page // Account page
mux.Handle("GET /account", route("GET /account", loggedIn(handler.AccountPage()))
middleware.RequiresLogin( route("POST /account-select-page", loggedIn(handler.AccountSubpage()))
handlers.HandleAccountPage(), route("POST /change-username", loggedIn(fresh(handler.ChangeUsername(logger, conn))))
)) route("POST /change-bio", loggedIn(handler.ChangeBio(logger, conn)))
mux.Handle("POST /account-select-page", route("POST /change-password", loggedIn(fresh(handler.ChangePassword(logger, conn))))
middleware.RequiresLogin(
handlers.HandleAccountSubpage(),
))
mux.Handle("POST /change-username",
middleware.RequiresLogin(
middleware.RequiresFresh(
handlers.HandleChangeUsername(logger, conn),
),
))
mux.Handle("POST /change-bio",
middleware.RequiresLogin(
handlers.HandleChangeBio(logger, conn),
))
mux.Handle("POST /change-password",
middleware.RequiresLogin(
middleware.RequiresFresh(
handlers.HandleChangePassword(logger, conn),
),
))
} }

View File

@@ -33,7 +33,7 @@ templ LoginForm(loginError string) {
<!-- Form Group --> <!-- Form Group -->
<div> <div>
<label <label
for="email" for="username"
class="block text-sm mb-2" class="block text-sm mb-2"
>Username</label> >Username</label>
<div class="relative"> <div class="relative">

View File

@@ -38,7 +38,7 @@ templ RegisterForm(registerError string) {
> >
<div> <div>
<label <label
for="email" for="username"
class="block text-sm mb-2" class="block text-sm mb-2"
>Username</label> >Username</label>
<div class="relative"> <div class="relative">