Setup admin groups, admin panel view, installation process

This commit is contained in:
yequari 2025-08-23 14:09:34 -07:00
parent 00f7fb13c1
commit 8d705c957b
21 changed files with 1443 additions and 49 deletions

61
cmd/web/handlers_admin.go Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"errors"
"fmt"
"net/http"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"git.32bit.cafe/32bitcafe/guestbook/ui/views"
)
func (app *application) getAdminPanelLanding(w http.ResponseWriter, r *http.Request) {
data := app.newCommonData(r)
views.AdminPanelLandingView("Admin Panel", data).Render(r.Context(), w)
}
func (app *application) getAdminPanelAllUsers(w http.ResponseWriter, r *http.Request) {
users, err := app.users.GetAll()
if err != nil {
app.serverError(w, r, err)
return
}
data := app.newCommonData(r)
views.AdminPanelUsersView("All Users - Admin", data, users).Render(r.Context(), w)
}
func (app *application) getAdminPanelUser(w http.ResponseWriter, r *http.Request) {
slug := r.PathValue("id")
u, err := app.users.Get(slugToShortId(slug))
if err != nil {
if errors.Is(err, models.ErrNoRecord) {
http.NotFound(w, r)
} else {
app.serverError(w, r, err)
}
return
}
data := app.newCommonData(r)
views.AdminPanelUserMgmtView(fmt.Sprintf("User Management - %s", u.Username), data, u).Render(r.Context(), w)
}
func (app *application) putAdminPanelBanUser(w http.ResponseWriter, r *http.Request) {
slug := r.PathValue("id")
u, err := app.users.Get(slugToShortId(slug))
if err != nil {
if errors.Is(err, models.ErrNoRecord) {
http.NotFound(w, r)
} else {
app.serverError(w, r, err)
}
return
}
err = app.users.BanUser(u.ID)
if err != nil {
app.serverError(w, r, err)
return
}
}
func (app *application) getAdminPanelWebsites(w http.ResponseWriter, r *http.Request) {
}

69
cmd/web/installer.go Normal file
View File

@ -0,0 +1,69 @@
package main
import (
"net/http"
"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"git.32bit.cafe/32bitcafe/guestbook/internal/validator"
"git.32bit.cafe/32bitcafe/guestbook/ui"
"git.32bit.cafe/32bitcafe/guestbook/ui/views"
"github.com/justinas/alice"
)
func (i *appInstaller) installRoutes() http.Handler {
mux := http.NewServeMux()
if i.app.config.environment == "PROD" {
mux.Handle("GET /static/", http.FileServerFS(ui.Files))
} else {
fileServer := http.FileServer(http.Dir("./ui/static/"))
mux.Handle("GET /static/", http.StripPrefix("/static", fileServer))
}
mux.HandleFunc("GET /ping", ping)
standard := alice.New(i.app.recoverPanic, i.app.logRequest, commonHeaders)
mux.Handle("/{$}", standard.ThenFunc(i.getInstallHomepage))
mux.Handle("GET /install", standard.ThenFunc(i.getInstallForm))
mux.Handle("POST /install", standard.ThenFunc(i.postInstallForm))
return standard.Then(mux)
}
func (i *appInstaller) getInstallHomepage(w http.ResponseWriter, r *http.Request) {
views.InitialInstallView("Installation").Render(r.Context(), w)
}
func (i *appInstaller) getInstallForm(w http.ResponseWriter, r *http.Request) {
var form forms.InstallForm
views.InstallFormView("Installation - Settings", form).Render(r.Context(), w)
}
func (i *appInstaller) postInstallForm(w http.ResponseWriter, r *http.Request) {
var form forms.InstallForm
err := i.app.decodePostForm(r, &form)
if err != nil {
i.app.clientError(w, http.StatusBadRequest)
return
}
form.CheckField(validator.NotBlank(form.Name), "name", "This field cannot be blank")
form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
form.CheckField(validator.MinChars(form.Password, 8), "password", "This field must be at least 8 characters long")
if !form.Valid() {
w.WriteHeader(http.StatusUnprocessableEntity)
views.InstallFormView("User Registration", form).Render(r.Context(), w)
return
}
sId := i.app.createShortId()
err = i.app.users.Insert(sId, form.Name, form.Email, form.Password, DefaultUserSettings())
if err != nil {
i.app.serverError(w, r, err)
}
err = i.app.users.AddUserToGroup(1, models.AdminGroup)
if err != nil {
i.app.serverError(w, r, err)
}
views.InstallSuccessView().Render(r.Context(), w)
i.srv.Close()
}

View File

@ -56,6 +56,12 @@ type application struct {
timezones []string
}
type appInstaller struct {
app *application
srv *http.Server
installModel models.InstallModelInterface
}
func main() {
addr := flag.String("addr", ":3000", "HTTP network address")
dsn := flag.String("dsn", "guestbook.db", "data source name")
@ -102,6 +108,29 @@ func main() {
timezones: getAvailableTimezones(),
}
tlsConfig := &tls.Config{
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
}
installer := &appInstaller{
app: app,
installModel: &models.InstallModel{DB: db},
}
installer.srv = &http.Server{
Addr: *addr,
Handler: installer.installRoutes(),
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
TLSConfig: tlsConfig,
IdleTimeout: time.Minute,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
err = runInstaller(installer)
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
err = app.users.InitializeSettingsMap()
if err != nil {
logger.Error(err.Error())
@ -113,10 +142,6 @@ func main() {
os.Exit(1)
}
tlsConfig := &tls.Config{
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
}
srv := &http.Server{
Addr: *addr,
Handler: app.routes(),
@ -273,3 +298,31 @@ func walkTzDir(path string, zones []string) []string {
return zones
}
func runInstaller(i *appInstaller) error {
i.app.logger.Info("Performing migrations")
err := i.installModel.SetupDatabase()
if err != nil {
return err
}
installed, _ := i.installModel.GetInstalledFlag()
if installed {
return nil
}
i.app.logger.Info("App not installed, running installer...")
i.app.logger.Info("Starting installation server", slog.Any("addr", i.srv.Addr))
if i.app.debug {
err = i.srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem")
} else {
err = i.srv.ListenAndServe()
}
if err != nil && !errors.Is(err, http.ErrServerClosed) {
return err
}
i.app.logger.Info("Installation complete")
err = i.installModel.SetInstalledFlag()
if err != nil {
return err
}
return nil
}

View File

@ -4,7 +4,9 @@ import (
"context"
"fmt"
"net/http"
"slices"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"github.com/justinas/nosurf"
)
@ -56,6 +58,17 @@ func (app *application) requireAuthentication(next http.Handler) http.Handler {
})
}
func (app *application) requireAdmin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := app.getCurrentUser(r)
if !slices.Contains(user.Groups, models.AdminGroup) {
app.clientError(w, http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
func noSurf(next http.Handler) http.Handler {
csrfHandler := nosurf.New(next)
csrfHandler.SetBaseCookie(http.Cookie{
@ -84,6 +97,9 @@ func (app *application) authenticate(next http.Handler) http.Handler {
app.serverError(w, r, err)
return
}
if !user.Banned.IsZero() {
http.Redirect(w, r, "/banned", http.StatusSeeOther)
}
if exists {
ctx := context.WithValue(r.Context(), isAuthenticatedContextKey, true)
ctx = context.WithValue(ctx, userNameContextKey, user)

View File

@ -39,13 +39,11 @@ func (app *application) routes() http.Handler {
protected := dynamic.Append(app.requireAuthentication)
// mux.Handle("GET /users", protected.ThenFunc(app.getUsersList))
mux.Handle("GET /users/{id}", protected.ThenFunc(app.getUser))
mux.Handle("POST /users/logout", protected.ThenFunc(app.postUserLogout))
mux.Handle("GET /users/settings", protected.ThenFunc(app.getUserSettings))
mux.Handle("PUT /users/settings", protected.ThenFunc(app.putUserSettings))
mux.Handle("GET /guestbooks", protected.ThenFunc(app.getAllGuestbooks))
mux.Handle("GET /websites", protected.ThenFunc(app.getWebsiteList))
mux.Handle("GET /websites/create", protected.ThenFunc(app.getWebsiteCreate))
mux.Handle("POST /websites/create", protected.ThenFunc(app.postWebsiteCreate))
@ -60,5 +58,10 @@ func (app *application) routes() http.Handler {
mux.Handle("GET /websites/{id}/dashboard/guestbook/themes", protected.ThenFunc(app.getComingSoon))
mux.Handle("GET /websites/{id}/dashboard/guestbook/customize", protected.ThenFunc(app.getComingSoon))
adminOnly := protected.Append(app.requireAdmin)
mux.Handle("GET /admin", adminOnly.ThenFunc(app.getAdminPanelLanding))
mux.Handle("GET /admin/users", adminOnly.ThenFunc(app.getAdminPanelAllUsers))
mux.Handle("GET /admin/users/{id}", adminOnly.ThenFunc(app.getAdminPanelUser))
return standard.Then(mux)
}

View File

@ -25,9 +25,9 @@ type CommentCreateForm struct {
}
type WebsiteCreateForm struct {
Name string `schema:"sitename"`
SiteUrl string `schema:"siteurl"`
AuthorName string `schema:"authorname"`
Name string `schema:"ws_name""`
SiteUrl string `schema:"ws_url"`
AuthorName string `schema:"ws_author"`
validator.Validator `schema:"-"`
}
@ -50,3 +50,13 @@ type WebsiteSettingsForm struct {
WidgetsEnabled string `schema:"gb_remote"`
validator.Validator `schema:"-"`
}
type AdminUserMgmtForm struct {
}
type InstallForm struct {
Name string `schema:"username"`
Email string `schema:"email"`
Password string `schema:"password"`
validator.Validator `schema:"-"`
}

View File

@ -0,0 +1,62 @@
package models
import (
"database/sql"
"errors"
"time"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
_ "github.com/golang-migrate/migrate/v4/source/file"
_ "github.com/mattn/go-sqlite3"
)
type InstallModel struct {
DB *sql.DB
}
type InstallModelInterface interface {
SetupDatabase() error
SetInstalledFlag() error
GetInstalledFlag() (bool, error)
}
func (m *InstallModel) SetupDatabase() error {
driver, err := sqlite3.WithInstance(m.DB, &sqlite3.Config{})
if err != nil {
return err
}
mi, err := migrate.NewWithDatabaseInstance("file://migrations", "sqlite", driver)
if err != nil {
return err
}
err = mi.Up()
if err != nil && !errors.Is(err, migrate.ErrNoChange) {
return err
}
return nil
}
func (m *InstallModel) SetInstalledFlag() error {
stmt := `INSERT INTO installed (InstallDate) VALUES (?)`
_, err := m.DB.Exec(stmt, time.Now().UTC())
if err != nil {
return err
}
return nil
}
func (m *InstallModel) GetInstalledFlag() (bool, error) {
stmt := `SELECT InstallDate FROM installed`
row := m.DB.QueryRow(stmt)
var d time.Time
err := row.Scan(&d)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return false, nil
} else {
return false, err
}
}
return true, nil
}

View File

@ -13,7 +13,6 @@ var mockUser = models.User{
Username: "tester",
Email: "test@example.com",
Deleted: false,
IsBanned: false,
Created: time.Now(),
Settings: mockUserSettings,
}
@ -120,3 +119,7 @@ func (m *UserModel) UpdateSubject(userId int64, subject string) error {
}
return errors.New("invalid")
}
func (m *UserModel) GetNumberOfUsers() int {
return 1
}

View File

@ -10,6 +10,13 @@ import (
"golang.org/x/crypto/bcrypt"
)
type UserGroupId int64
const (
AdminGroup UserGroupId = 1
UserGroup UserGroupId = 2
)
type UserSettings struct {
LocalTimezone *time.Location
}
@ -24,10 +31,11 @@ type User struct {
Username string
Email string
Deleted bool
IsBanned bool
HashedPassword []byte
Created time.Time
Banned time.Time
Settings UserSettings
Groups []UserGroupId
}
type UserModel struct {
@ -57,6 +65,9 @@ type UserModelInterface interface {
UpdateUserSettings(userId int64, settings UserSettings) error
UpdateSetting(userId int64, setting Setting, value string) error
UpdateSubject(userId int64, subject string) error
GetNumberOfUsers() int
AddUserToGroup(userId int64, groupId UserGroupId) error
BanUser(userId int64) error
}
func (m *UserModel) InitializeSettingsMap() error {
@ -96,8 +107,8 @@ func (m *UserModel) Insert(shortId uint64, username string, email string, passwo
if err != nil {
return err
}
stmt := `INSERT INTO users (ShortId, Username, Email, IsBanned, HashedPassword, Created)
VALUES (?, ?, ?, FALSE, ?, ?)`
stmt := `INSERT INTO users (ShortId, Username, Email, HashedPassword, Created)
VALUES (?, ?, ?, ?, ?)`
tx, err := m.DB.Begin()
if err != nil {
return err
@ -107,7 +118,8 @@ func (m *UserModel) Insert(shortId uint64, username string, email string, passwo
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return err
}
if sqliteError, ok := err.(sqlite3.Error); ok {
var sqliteError sqlite3.Error
if errors.As(err, &sqliteError) {
if sqliteError.ExtendedCode == 2067 && strings.Contains(sqliteError.Error(), "Email") {
return ErrDuplicateEmail
}
@ -130,17 +142,20 @@ func (m *UserModel) Insert(shortId uint64, username string, email string, passwo
}
return err
}
err = m.addUserToGroup(tx, id, UserGroup)
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func (m *UserModel) InsertWithoutPassword(shortId uint64, username string, email string, subject string, settings UserSettings) (int64, error) {
stmt := `INSERT INTO users (ShortId, Username, Email, IsBanned, OIDCSubject, Created)
VALUES (?, ?, ?, FALSE, ?, ?)`
stmt := `INSERT INTO users (ShortId, Username, Email, OIDCSubject, Created)
VALUES (?, ?, ?, ?, ?)`
tx, err := m.DB.Begin()
if err != nil {
return -1, err
@ -150,7 +165,8 @@ func (m *UserModel) InsertWithoutPassword(shortId uint64, username string, email
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return -1, err
}
if sqliteError, ok := err.(sqlite3.Error); ok {
var sqliteError sqlite3.Error
if errors.As(err, &sqliteError) {
if sqliteError.ExtendedCode == 2067 && strings.Contains(sqliteError.Error(), "Email") {
return -1, ErrDuplicateEmail
}
@ -173,6 +189,7 @@ func (m *UserModel) InsertWithoutPassword(shortId uint64, username string, email
}
return -1, err
}
err = m.addUserToGroup(tx, id, UserGroup)
err = tx.Commit()
if err != nil {
return -1, err
@ -182,14 +199,15 @@ func (m *UserModel) InsertWithoutPassword(shortId uint64, username string, email
}
func (m *UserModel) Get(shortId uint64) (User, error) {
stmt := `SELECT Id, ShortId, Username, Email, Created FROM users WHERE ShortId = ? AND Deleted IS NULL`
stmt := `SELECT Id, ShortId, Username, Email, Created, Banned FROM users WHERE ShortId = ? AND Deleted IS NULL`
tx, err := m.DB.Begin()
if err != nil {
return User{}, err
}
row := tx.QueryRow(stmt, shortId)
var u User
err = row.Scan(&u.ID, &u.ShortId, &u.Username, &u.Email, &u.Created)
var b sql.NullTime
err = row.Scan(&u.ID, &u.ShortId, &u.Username, &u.Email, &u.Created, &b)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return User{}, err
@ -199,6 +217,9 @@ func (m *UserModel) Get(shortId uint64) (User, error) {
}
return User{}, err
}
if b.Valid {
u.Banned = b.Time
}
settings, err := m.getSettings(tx, u.ID)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
@ -207,6 +228,14 @@ func (m *UserModel) Get(shortId uint64) (User, error) {
return User{}, err
}
u.Settings = settings
groups, err := m.getGroups(tx, u.ID)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return User{}, err
}
return User{}, err
}
u.Groups = groups
err = tx.Commit()
if err != nil {
return User{}, err
@ -215,14 +244,15 @@ func (m *UserModel) Get(shortId uint64) (User, error) {
}
func (m *UserModel) GetById(id int64) (User, error) {
stmt := `SELECT Id, ShortId, Username, Email, Created FROM users WHERE Id = ? AND Deleted IS NULL`
stmt := `SELECT Id, ShortId, Username, Email, Created, Banned FROM users WHERE Id = ? AND Deleted IS NULL`
tx, err := m.DB.Begin()
if err != nil {
return User{}, err
}
row := tx.QueryRow(stmt, id)
var u User
err = row.Scan(&u.ID, &u.ShortId, &u.Username, &u.Email, &u.Created)
var b sql.NullTime
err = row.Scan(&u.ID, &u.ShortId, &u.Username, &u.Email, &u.Created, &b)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return User{}, err
@ -232,6 +262,9 @@ func (m *UserModel) GetById(id int64) (User, error) {
}
return User{}, err
}
if b.Valid {
u.Banned = b.Time
}
settings, err := m.getSettings(tx, u.ID)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
@ -240,6 +273,14 @@ func (m *UserModel) GetById(id int64) (User, error) {
return User{}, err
}
u.Settings = settings
groups, err := m.getGroups(tx, u.ID)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return User{}, err
}
return User{}, err
}
u.Groups = groups
err = tx.Commit()
if err != nil {
return User{}, err
@ -400,3 +441,66 @@ func (m *UserModel) UpdateSetting(userId int64, setting Setting, value string) e
}
return nil
}
func (m *UserModel) GetNumberOfUsers() int {
stmt := `SELECT COUNT(Id) FROM users WHERE Deleted IS NULL;`
row := m.DB.QueryRow(stmt)
var count int
err := row.Scan(&count)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
count = 0
} else {
count = 1
}
}
return count
}
func (m *UserModel) AddUserToGroup(userId int64, groupId UserGroupId) error {
stmt := `INSERT INTO users_groups (UserId, GroupId) VALUES (?, ?)`
_, err := m.DB.Exec(stmt, userId, groupId)
if err != nil {
return err
}
return nil
}
func (m *UserModel) BanUser(userId int64) error {
stmt := `UPDATE users SET Banned=? WHERE Id=?`
_, err := m.DB.Exec(stmt, time.Now().UTC().Format(time.RFC3339), userId)
if err != nil {
return err
}
return nil
}
func (m *UserModel) addUserToGroup(tx *sql.Tx, userId int64, groupId UserGroupId) error {
stmt := `INSERT INTO users_groups (UserId, GroupId) VALUES (?, ?)`
_, err := tx.Exec(stmt, userId, groupId)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return err
}
return err
}
return nil
}
func (m *UserModel) getGroups(tx *sql.Tx, userId int64) ([]UserGroupId, error) {
stmt := `SELECT DISTINCT GroupId FROM users_groups WHERE UserId = ?`
rows, err := tx.Query(stmt, userId)
result := make([]UserGroupId, 0, 10)
if err != nil {
return result, err
}
for rows.Next() {
var g UserGroupId
err = rows.Scan(&g)
if err != nil {
return result, err
}
result = append(result, g)
}
return result, nil
}

View File

@ -0,0 +1,2 @@
DROP TABLE IF EXISTS users_groups;
DROP TABLE IF EXISTS groups;

View File

@ -0,0 +1,19 @@
CREATE TABLE IF NOT EXISTS groups (
Id integer PRIMARY KEY NOT NULL,
Description varchar(256)
);
INSERT INTO groups (Id, Description)
VALUES (1, 'admin'),(2, 'user');
CREATE TABLE IF NOT EXISTS users_groups (
Id integer primary key autoincrement,
UserId integer NOT NULL,
GroupId integer NOT NULL,
FOREIGN KEY (UserId) REFERENCES users(Id)
ON DELETE RESTRICT
ON UPDATE RESTRICT,
FOREIGN KEY (GroupId) REFERENCES groups(Id)
ON DELETE RESTRICT
ON UPDATE RESTRICT
);

View File

@ -0,0 +1,2 @@
ALTER TABLE users DROP COLUMN Banned;
ALTER TABLE users ADD COLUMN IsBanned boolean NOT NULL DEFAULT false;

View File

@ -0,0 +1,2 @@
ALTER TABLE users DROP COLUMN IsBanned;
ALTER TABLE users ADD COLUMN Banned datetime NULL;

View File

@ -0,0 +1 @@
DROP TABLE IF EXISTS installed;

View File

@ -0,0 +1,5 @@
CREATE TABLE installed (
Id integer primary key autoincrement,
InstallDate datetime NOT NULL,
InstallVersion varchar(100) NULL
);

117
ui/views/admin.templ Normal file
View File

@ -0,0 +1,117 @@
package views
import (
"fmt"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"time"
)
templ adminBase(title string, data CommonData) {
<!DOCTYPE html>
<html lang="en">
<head>
<title>{ title } - webweav.ing</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="htmx-config" content={ `{"includeIndicatorStyles":false}` }/>
<link href="/static/css/style.css" rel="stylesheet"/>
<link href="/static/fontawesome/css/fontawesome.css" rel="stylesheet"/>
<link href="/static/fontawesome/css/solid.css" rel="stylesheet"/>
<script src="/static/js/htmx.min.js"></script>
</head>
<body>
<header>
<a href="/">Back to webweav.ing</a>
</header>
<main>
{ children... }
</main>
@commonFooter()
</body>
</html>
}
templ adminSidebar() {
<nav aria-label="Admin panel navigation">
<div>
<section>
<h3>Administration</h3>
<ul role="list">
<li><a href="/admin/users">Users</a></li>
<li><a href="/admin/guestbooks">Guestbooks</a></li>
<li><a href="/admin/comments">Comments</a></li>
</ul>
</section>
</div>
</nav>
}
templ AdminPanelLandingView(title string, data CommonData) {
@adminBase(title, data) {
<div id="dashboard">
@adminSidebar()
<div>
<h1>{ title }</h1>
<p>Welcome to the admin panel</p>
</div>
</div>
}
}
templ AdminPanelUsersView(title string, data CommonData, users []models.User) {
@adminBase(title, data) {
<div id="dashboard">
@adminSidebar()
<div>
<section>
<table>
<th>Username</th>
<th>Joined</th>
<th>Email</th>
<tr>
for _, u := range users {
{{ url := fmt.Sprintf("/admin/users/%s", shortIdToSlug(u.ShortId)) }}
<td><a href={ templ.URL(url) }>{ u.Username }</a></td>
<td>{ u.Created.Format(time.RFC3339) }</td>
<td>{ u.Email }</td>
}
</tr>
</table>
</section>
</div>
</div>
}
}
templ AdminPanelUserMgmtView(title string, data CommonData, user models.User) {
@adminBase(title, data) {
<div id="dashboard">
@adminSidebar()
<div>
<section>
<h3>User Info</h3>
<div>
<h5>Username</h5>
<p>{ user.Username }</p>
</div>
<div>
<h5>Email</h5>
<p>{ user.Email }</p>
</div>
<div>
<h5>Joined</h5>
<p>{ user.Created.Format(time.RFC3339) }</p>
</div>
</section>
<section>
<h3>Groups</h3>
<ul>
for _, g := range user.Groups {
<li>{ fmt.Sprintf("%d %s", g, getGroupName(g)) }</li>
}
</ul>
</section>
</div>
</div>
}
}

416
ui/views/admin_templ.go Normal file
View File

@ -0,0 +1,416 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.833
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"fmt"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"time"
)
func adminBase(title string, data CommonData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 13, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " - webweav.ing</title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta name=\"htmx-config\" content=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(`{"includeIndicatorStyles":false}`)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 16, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><link href=\"/static/css/style.css\" rel=\"stylesheet\"><link href=\"/static/fontawesome/css/fontawesome.css\" rel=\"stylesheet\"><link href=\"/static/fontawesome/css/solid.css\" rel=\"stylesheet\"><script src=\"/static/js/htmx.min.js\"></script></head><body><header><a href=\"/\">Back to webweav.ing</a></header><main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = commonFooter().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func adminSidebar() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<nav aria-label=\"Admin panel navigation\"><div><section><h3>Administration</h3><ul role=\"list\"><li><a href=\"/admin/users\">Users</a></li><li><a href=\"/admin/guestbooks\">Guestbooks</a></li><li><a href=\"/admin/comments\">Comments</a></li></ul></section></div></nav>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func AdminPanelLandingView(title string, data CommonData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div id=\"dashboard\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = adminSidebar().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<div><h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 54, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</h1><p>Welcome to the admin panel</p></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = adminBase(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func AdminPanelUsersView(title string, data CommonData, users []models.User) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div id=\"dashboard\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = adminSidebar().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div><section><table><th>Username</th><th>Joined</th><th>Email</th><tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, u := range users {
url := fmt.Sprintf("/admin/users/%s", shortIdToSlug(u.ShortId))
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<td><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 templ.SafeURL = templ.URL(url)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(u.Username)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 74, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</a></td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(u.Created.Format(time.RFC3339))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 75, Col: 44}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(u.Email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 76, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</tr></table></section></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = adminBase(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func AdminPanelUserMgmtView(title string, data CommonData, user models.User) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var14 := templ.GetChildren(ctx)
if templ_7745c5c3_Var14 == nil {
templ_7745c5c3_Var14 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var15 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<div id=\"dashboard\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = adminSidebar().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<div><section><h3>User Info</h3><div><h5>Username</h5><p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 95, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</p></div><div><h5>Email</h5><p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 99, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</p></div><div><h5>Joined</h5><p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(user.Created.Format(time.RFC3339))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 103, Col: 44}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</p></div></section><section><h3>Groups</h3><ul>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, g := range user.Groups {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d %s", g, getGroupName(g)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/admin.templ`, Line: 110, Col: 53}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</ul></section></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = adminBase(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var15), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,9 +1,12 @@
package views
import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
import "strconv"
import "fmt"
import "strings"
import (
"fmt"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"slices"
"strconv"
"strings"
)
type CommonData struct {
CurrentYear int
@ -33,6 +36,16 @@ func externalUrl(url string) string {
return url
}
func getGroupName(id models.UserGroupId) string {
switch id {
case 1:
return "Admin"
case 2:
return "User"
}
return "Unknown"
}
templ commonHeader() {
<header>
<h1><a href="/">webweav.ing</a></h1>
@ -54,6 +67,9 @@ templ topNav(data CommonData) {
<li><a href="/guestbooks">All Guestbooks</a></li>
<li><a href="/websites">My Websites</a></li>
<li><a href="/users/settings">Settings</a></li>
if slices.Contains(data.CurrentUser.Groups, models.AdminGroup) {
<li><a href="/admin">Admin Panel</a></li>
}
<li><a href="#" hx-post="/users/logout" hx-headers={ hxHeaders }>Logout</a></li>
} else {
if data.LocalAuthEnabled {

View File

@ -8,10 +8,13 @@ package views
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
import "strconv"
import "fmt"
import "strings"
import (
"fmt"
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
"slices"
"strconv"
"strings"
)
type CommonData struct {
CurrentYear int
@ -41,6 +44,16 @@ func externalUrl(url string) string {
return url
}
func getGroupName(id models.UserGroupId) string {
switch id {
case 1:
return "Admin"
case 2:
return "User"
}
return "Unknown"
}
func commonHeader() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -104,7 +117,7 @@ func topNav(data CommonData) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.CurrentUser.Username)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 48, Col: 41}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 61, Col: 41}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@ -116,36 +129,46 @@ func topNav(data CommonData) templ.Component {
return templ_7745c5c3_Err
}
if data.IsAuthenticated {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<li><a href=\"/guestbooks\">All Guestbooks</a></li><li><a href=\"/websites\">My Websites</a></li><li><a href=\"/users/settings\">Settings</a></li><li><a href=\"#\" hx-post=\"/users/logout\" hx-headers=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<li><a href=\"/guestbooks\">All Guestbooks</a></li><li><a href=\"/websites\">My Websites</a></li><li><a href=\"/users/settings\">Settings</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if slices.Contains(data.CurrentUser.Groups, models.AdminGroup) {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<li><a href=\"/admin\">Admin Panel</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " <li><a href=\"#\" hx-post=\"/users/logout\" hx-headers=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(hxHeaders)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 57, Col: 66}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 73, Col: 66}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">Logout</a></li>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">Logout</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
if data.LocalAuthEnabled {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<li><a href=\"/users/register\">Create an Account</a></li>| ")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<li><a href=\"/users/register\">Create an Account</a></li>| ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, " <li><a href=\"/users/login\">Login</a></li>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " <li><a href=\"/users/login\">Login</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</ul></nav>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</ul></nav>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -174,7 +197,7 @@ func commonFooter() templ.Component {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<footer><p>A <a href=\"https://32bit.cafe\" rel=\"noopener\">32bit.cafe</a> Project</p><ul class=\"footer-links\"><li><a href=\"/about\">About</a></li><li><a href=\"/help\">Help</a></li></ul></footer>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<footer><p>A <a href=\"https://32bit.cafe\" rel=\"noopener\">32bit.cafe</a> Project</p><ul class=\"footer-links\"><li><a href=\"/about\">About</a></li><li><a href=\"/help\">Help</a></li></ul></footer>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -203,33 +226,33 @@ func base(title string, data CommonData) templ.Component {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<!doctype html><html lang=\"en\"><head><title>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<!doctype html><html lang=\"en\"><head><title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 82, Col: 17}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 98, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " - webweav.ing</title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta name=\"htmx-config\" content=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " - webweav.ing</title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta name=\"htmx-config\" content=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(`{"includeIndicatorStyles":false}`)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 85, Col: 72}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 101, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"><link href=\"/static/css/style.css\" rel=\"stylesheet\"><link href=\"/static/fontawesome/css/fontawesome.css\" rel=\"stylesheet\"><link href=\"/static/fontawesome/css/solid.css\" rel=\"stylesheet\"><script src=\"/static/js/htmx.min.js\"></script></head><body>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\"><link href=\"/static/css/style.css\" rel=\"stylesheet\"><link href=\"/static/fontawesome/css/fontawesome.css\" rel=\"stylesheet\"><link href=\"/static/fontawesome/css/solid.css\" rel=\"stylesheet\"><script src=\"/static/js/htmx.min.js\"></script></head><body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -241,25 +264,25 @@ func base(title string, data CommonData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<main role=\"main\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<main role=\"main\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Flash != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<div class=\"notice flash\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<div class=\"notice flash\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(data.Flash)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 96, Col: 43}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 112, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -268,7 +291,7 @@ func base(title string, data CommonData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</main>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -276,7 +299,7 @@ func base(title string, data CommonData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</body></html>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

75
ui/views/install.templ Normal file
View File

@ -0,0 +1,75 @@
package views
import "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
templ installBase(title string) {
<!DOCTYPE html>
<html lang="en">
<head>
<title>{ title } - webweav.ing</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link href="/static/css/style.css" rel="stylesheet"/>
<script src="/static/js/htmx.min.js"></script>
</head>
<body>
<main>
<h1>{ title }</h1>
{ children... }
</main>
@commonFooter()
</body>
</html>
}
templ InitialInstallView(title string) {
@installBase(title) {
<p>Installing</p>
<a href="/install">Next</a>
}
}
templ InstallFormView(title string, form forms.InstallForm) {
@installBase(title) {
<form action="/install" method="post">
<fieldset>
<legend>Admin User</legend>
<div class="form-group">
<div>
{{ error, exists := form.FieldErrors[""] }}
<label for="username">Username: </label>
if exists {
<label class="error">{ error }</label>
}
<input type="text" name="username" id="username" value={ form.Name } required/>
</div>
<div>
{{ error, exists = form.FieldErrors["email"] }}
<label for="email">Email: </label>
if exists {
<label class="error">{ error }</label>
}
<input type="text" name="email" id="email" value={ form.Email } required/>
</div>
<div>
{{ error, exists = form.FieldErrors["password"] }}
<label for="password">Password: </label>
if exists {
<label class="error">{ error }</label>
}
<input type="password" name="password" id="password"/>
</div>
</div>
</fieldset>
<div>
<input type="submit" value="Install"/>
</div>
</form>
}
}
templ InstallSuccessView() {
@installBase("Success") {
<p>Installation was successful. Go <a href="/">home</a>.</p>
}
}

335
ui/views/install_templ.go Normal file
View File

@ -0,0 +1,335 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.833
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
func installBase(title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 9, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " - webweav.ing</title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><link href=\"/static/css/style.css\" rel=\"stylesheet\"><script src=\"/static/js/htmx.min.js\"></script></head><body><main><h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 17, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = commonFooter().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func InitialInstallView(title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var5 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<p>Installing</p><a href=\"/install\">Next</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = installBase(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func InstallFormView(title string, form forms.InstallForm) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<form action=\"/install\" method=\"post\"><fieldset><legend>Admin User</legend><div class=\"form-group\"><div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
error, exists := form.FieldErrors[""]
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<label for=\"username\">Username: </label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if exists {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<label class=\"error\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(error)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 42, Col: 35}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<input type=\"text\" name=\"username\" id=\"username\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(form.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 44, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" required></div><div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
error, exists = form.FieldErrors["email"]
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<label for=\"email\">Email: </label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if exists {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<label class=\"error\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(error)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 50, Col: 35}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<input type=\"text\" name=\"email\" id=\"email\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(form.Email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 52, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" required></div><div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
error, exists = form.FieldErrors["password"]
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<label for=\"password\">Password: </label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if exists {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<label class=\"error\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(error)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/install.templ`, Line: 58, Col: 35}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<input type=\"password\" name=\"password\" id=\"password\"></div></div></fieldset><div><input type=\"submit\" value=\"Install\"></div></form>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = installBase(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func InstallSuccessView() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var13 := templ.GetChildren(ctx)
if templ_7745c5c3_Var13 == nil {
templ_7745c5c3_Var13 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var14 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<p>Installation was successful. Go <a href=\"/\">home</a>.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = installBase("Success").Render(templ.WithChildren(ctx, templ_7745c5c3_Var14), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate