remove preact and create setup wizard

This commit is contained in:
2026-06-01 10:10:36 -04:00
parent b3364447a1
commit ebe0920f89
53 changed files with 818 additions and 4226 deletions

View File

@@ -100,6 +100,93 @@ func (r *Repository) CountAdmins(ctx context.Context) (int, error) {
return count, nil
}
func (r *Repository) GetInstanceSettings(ctx context.Context) (InstanceSettings, error) {
var setupCompleted string
var signupsEnabled int
if err := r.db.QueryRowContext(ctx, `
SELECT COALESCE(setup_completed_at, ''), signups_enabled
FROM instance_settings
WHERE id = 1
`).Scan(&setupCompleted, &signupsEnabled); err != nil {
return InstanceSettings{}, fmt.Errorf("get instance settings: %w", err)
}
return InstanceSettings{
SetupComplete: setupCompleted != "",
SignupsEnabled: signupsEnabled == 1,
}, nil
}
func (r *Repository) CompleteInitialSetup(ctx context.Context, user User, signupsEnabled bool) (User, error) {
now := time.Now().UTC()
if user.ID == "" {
user.ID = "user:" + user.Email
}
if user.DisplayName == "" {
user.DisplayName = user.Email
}
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return User{}, fmt.Errorf("begin initial setup: %w", err)
}
defer func() { _ = tx.Rollback() }()
var setupCompleted string
if err := tx.QueryRowContext(ctx, `
SELECT COALESCE(setup_completed_at, '')
FROM instance_settings
WHERE id = 1
`).Scan(&setupCompleted); err != nil {
return User{}, fmt.Errorf("get initial setup state: %w", err)
}
if setupCompleted != "" {
return User{}, fmt.Errorf("initial setup has already been completed")
}
var userCount int
if err := tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM users`).Scan(&userCount); err != nil {
return User{}, fmt.Errorf("count users during initial setup: %w", err)
}
if userCount != 0 {
return User{}, fmt.Errorf("initial setup requires an empty user database")
}
if _, err := tx.ExecContext(ctx, `
INSERT INTO users (id, email, display_name, password_hash, role, created_at, last_seen_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
`, user.ID, user.Email, user.DisplayName, nullString(user.PasswordHash), string(RoleAdmin), now.Format(time.RFC3339), now.Format(time.RFC3339)); err != nil {
return User{}, fmt.Errorf("create initial admin: %w", err)
}
if _, err := tx.ExecContext(ctx, `
UPDATE instance_settings
SET setup_completed_at = ?, signups_enabled = ?, updated_at = ?
WHERE id = 1 AND setup_completed_at IS NULL
`, now.Format(time.RFC3339), boolInt(signupsEnabled), now.Format(time.RFC3339)); err != nil {
return User{}, fmt.Errorf("complete initial setup: %w", err)
}
if err := tx.Commit(); err != nil {
return User{}, fmt.Errorf("commit initial setup: %w", err)
}
return r.GetUserByEmail(ctx, user.Email)
}
func (r *Repository) UpdateSignupsEnabled(ctx context.Context, enabled bool) error {
result, err := r.db.ExecContext(ctx, `
UPDATE instance_settings
SET signups_enabled = ?, updated_at = ?
WHERE id = 1 AND setup_completed_at IS NOT NULL
`, boolInt(enabled), time.Now().UTC().Format(time.RFC3339))
if err != nil {
return fmt.Errorf("update signup setting: %w", err)
}
if rows, _ := result.RowsAffected(); rows == 0 {
return fmt.Errorf("initial setup is required")
}
return nil
}
func (r *Repository) ListUsers(ctx context.Context) ([]User, error) {
rows, err := r.db.QueryContext(ctx, `
SELECT id, email, COALESCE(display_name, ''), COALESCE(password_hash, ''), COALESCE(role, 'viewer'), created_at, COALESCE(last_seen_at, '')
@@ -522,6 +609,13 @@ func nullString(value string) any {
return value
}
func boolInt(value bool) int {
if value {
return 1
}
return 0
}
func timePtrString(value *time.Time) any {
if value == nil {
return nil