Added a site setting section

This commit is contained in:
Leon Mika 2026-03-09 21:47:02 +11:00
parent 499c0d8568
commit 0bd91de234
17 changed files with 856 additions and 36 deletions

View file

@ -111,6 +111,7 @@ Starting weiro without any arguments will start the server.
lh := handlers.LoginHandler{Config: cfg, AuthService: svcs.Auth}
ph := handlers.PostsHandler{PostService: svcs.Posts}
uh := handlers.UploadsHandler{UploadsService: svcs.Uploads}
ssh := handlers.SiteSettingsHandler{SiteService: svcs.Sites}
app.Get("/login", lh.Login)
app.Post("/login", lh.DoLogin)
@ -137,6 +138,9 @@ Starting weiro without any arguments will start the server.
siteGroup.Post("/uploads/pending/:guid/finalize", uh.UploadComplete)
siteGroup.Delete("/uploads/:uploadID", uh.Delete)
siteGroup.Get("/settings", ssh.General)
siteGroup.Post("/settings", ssh.UpdateGeneral)
app.Get("/", middleware.OptionalUser(svcs.Auth), ih.Index)
app.Get("/first-run", ih.FirstRun)
app.Post("/first-run", ih.FirstRunSubmit)

View file

@ -152,15 +152,3 @@ func (ph PostsHandler) Delete(c fiber.Ctx) error {
return c.Redirect().To("/")
}))
}
func (ph PostsHandler) Rebuild(c fiber.Ctx) error {
if err := ph.PostService.RebuildSite(c.Context()); err != nil {
return err
}
return accepts(c, json(func() any {
return fiber.Map{}
}), html(func(c fiber.Ctx) error {
return c.Redirect().To("/")
}))
}

52
handlers/sitesettings.go Normal file
View file

@ -0,0 +1,52 @@
package handlers
import (
"fmt"
"github.com/gofiber/fiber/v3"
"lmika.dev/lmika/weiro/models"
"lmika.dev/lmika/weiro/services/sites"
)
type SiteSettingsHandler struct {
SiteService *sites.Service
}
func (s *SiteSettingsHandler) General(ctx fiber.Ctx) error {
site := ctx.Locals("site").(models.Site)
return ctx.Render("sitesettings/general", fiber.Map{
"site": site,
"tzones": sites.ListZones(),
})
}
func (s *SiteSettingsHandler) UpdateGeneral(c fiber.Ctx) error {
site := c.Locals("site").(models.Site)
var params sites.UpdateSiteSettingsParams
if err := c.Bind().Body(&params); err != nil {
return err
}
params.SiteID = site.ID
if _, err := s.SiteService.UpdateSiteSettings(c.Context(), params); err != nil {
return err
}
return c.Redirect().To(fmt.Sprintf("/sites/%v/settings", +site.ID))
}
func (ph PostsHandler) Rebuild(c fiber.Ctx) error {
site := c.Locals("site").(models.Site)
if err := ph.PostService.RebuildSite(c.Context()); err != nil {
return err
}
return accepts(c, json(func() any {
return fiber.Map{}
}), html(func(c fiber.Ctx) error {
return c.Redirect().To(fmt.Sprintf("/sites/%v/settings", +site.ID))
}))
}

View file

@ -27,8 +27,9 @@ type Site struct {
GUID string
Created time.Time
Title string
Tagline string
Title string
Tagline string
Timezone string
}
type SitePublishTarget struct {

View file

@ -47,6 +47,7 @@ type Site struct {
Title string
Tagline string
CreatedAt int64
Timezone string
}
type Upload struct {

View file

@ -27,8 +27,9 @@ INSERT INTO sites (
guid,
title,
tagline,
timezone,
created_at
) VALUES (?, ?, ?, ?, ?)
) VALUES (?, ?, ?, ?, ?, ?)
RETURNING id
`
@ -37,6 +38,7 @@ type InsertSiteParams struct {
Guid string
Title string
Tagline string
Timezone string
CreatedAt int64
}
@ -46,6 +48,7 @@ func (q *Queries) InsertSite(ctx context.Context, arg InsertSiteParams) (int64,
arg.Guid,
arg.Title,
arg.Tagline,
arg.Timezone,
arg.CreatedAt,
)
var id int64
@ -98,7 +101,7 @@ func (q *Queries) SelectAllSitesWithOwners(ctx context.Context) ([]SelectAllSite
}
const selectSiteByGUID = `-- name: SelectSiteByGUID :one
SELECT id, owner_id, guid, title, tagline, created_at FROM sites WHERE guid = ?
SELECT id, owner_id, guid, title, tagline, created_at, timezone FROM sites WHERE guid = ?
`
func (q *Queries) SelectSiteByGUID(ctx context.Context, guid string) (Site, error) {
@ -111,12 +114,13 @@ func (q *Queries) SelectSiteByGUID(ctx context.Context, guid string) (Site, erro
&i.Title,
&i.Tagline,
&i.CreatedAt,
&i.Timezone,
)
return i, err
}
const selectSiteByID = `-- name: SelectSiteByID :one
SELECT id, owner_id, guid, title, tagline, created_at FROM sites WHERE id = ?
SELECT id, owner_id, guid, title, tagline, created_at, timezone FROM sites WHERE id = ?
`
func (q *Queries) SelectSiteByID(ctx context.Context, id int64) (Site, error) {
@ -129,12 +133,13 @@ func (q *Queries) SelectSiteByID(ctx context.Context, id int64) (Site, error) {
&i.Title,
&i.Tagline,
&i.CreatedAt,
&i.Timezone,
)
return i, err
}
const selectSitesOwnedByUser = `-- name: SelectSitesOwnedByUser :many
SELECT id, owner_id, guid, title, tagline, created_at FROM sites WHERE owner_id = ? ORDER BY title ASC
SELECT id, owner_id, guid, title, tagline, created_at, timezone FROM sites WHERE owner_id = ? ORDER BY title ASC
`
func (q *Queries) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ([]Site, error) {
@ -153,6 +158,7 @@ func (q *Queries) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ([]
&i.Title,
&i.Tagline,
&i.CreatedAt,
&i.Timezone,
); err != nil {
return nil, err
}
@ -166,3 +172,24 @@ func (q *Queries) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ([]
}
return items, nil
}
const updateSite = `-- name: UpdateSite :exec
UPDATE sites SET title = ?, tagline = ?, timezone = ? WHERE id = ?
`
type UpdateSiteParams struct {
Title string
Tagline string
Timezone string
ID int64
}
func (q *Queries) UpdateSite(ctx context.Context, arg UpdateSiteParams) error {
_, err := q.db.ExecContext(ctx, updateSite,
arg.Title,
arg.Tagline,
arg.Timezone,
arg.ID,
)
return err
}

View file

@ -46,6 +46,7 @@ func (db *Provider) SaveSite(ctx context.Context, site *models.Site) error {
Guid: site.GUID,
Title: site.Title,
Tagline: site.Tagline,
Timezone: site.Timezone,
CreatedAt: timeToInt(site.Created),
})
if err != nil {
@ -55,8 +56,12 @@ func (db *Provider) SaveSite(ctx context.Context, site *models.Site) error {
return nil
}
// No update query defined in sqlgen yet
return nil
return db.queries.UpdateSite(ctx, sqlgen.UpdateSiteParams{
Title: site.Title,
Tagline: site.Tagline,
Timezone: site.Timezone,
ID: site.ID,
})
}
func (db *Provider) HasUsersAndSites(ctx context.Context) (bool, error) {
@ -96,11 +101,12 @@ func (db *Provider) SelectAllSitesWithOwners(ctx context.Context) ([]SiteWithOwn
func dbSiteToSite(row sqlgen.Site) models.Site {
return models.Site{
ID: row.ID,
OwnerID: row.OwnerID,
GUID: row.Guid,
Title: row.Title,
Tagline: row.Tagline,
Created: time.Unix(row.CreatedAt, 0).UTC(),
ID: row.ID,
OwnerID: row.OwnerID,
GUID: row.Guid,
Title: row.Title,
Timezone: row.Timezone,
Tagline: row.Tagline,
Created: time.Unix(row.CreatedAt, 0).UTC(),
}
}

View file

@ -32,13 +32,20 @@ func (s *Service) UpdatePost(ctx context.Context, params CreatePostParams) (*mod
post.Title = params.Title
post.Body = params.Body
post.UpdatedAt = now
post.Slug = post.BestSlug()
oldState := post.State
switch strings.ToLower(params.Action) {
case "publish":
post.State = models.StatePublished
post.PublishedAt = now
// Set the published at with the site timezone, and reset the slug, so that the date
// is in the site timezone.
renderTZ, err := time.LoadLocation(site.Timezone)
if err != nil {
renderTZ = time.UTC
}
post.PublishedAt = now.In(renderTZ)
post.Slug = post.BestSlug()
case "save draft":
post.State = models.StateDraft
post.PublishedAt = time.Time{}

View file

@ -6,6 +6,7 @@ import (
"iter"
"log"
"os"
"time"
"emperror.dev/errors"
"github.com/go-openapi/runtime"
@ -71,10 +72,16 @@ func (p *Publisher) Publish(ctx context.Context, site models.Site) error {
}
func (p *Publisher) publishSite(ctx context.Context, pubSite pubmodel.Site, target models.SitePublishTarget) error {
renderTZ, err := time.LoadLocation(pubSite.Timezone)
if err != nil {
renderTZ = time.UTC
}
sb, err := sitebuilder.New(pubSite, sitebuilder.Options{
BasePosts: "/posts",
TemplatesFS: simplecss.FS,
FeedItems: 30,
RenderTZ: renderTZ,
})
if err != nil {
return err

View file

@ -77,10 +77,11 @@ func (s *Service) FirstRun(ctx context.Context, req FirstRunRequest) (newUser mo
}
newSite = models.Site{
Title: defaultIfEmpty(req.SiteName, "New Site"),
GUID: models.NewNanoID(),
OwnerID: newUser.ID,
Created: time.Now(),
Title: defaultIfEmpty(req.SiteName, "New Site"),
GUID: models.NewNanoID(),
OwnerID: newUser.ID,
Timezone: "UTC",
Created: time.Now(),
}
if err := s.db.SaveSite(ctx, &newSite); err != nil {
return newUser, newSite, err
@ -126,3 +127,32 @@ func (s *Service) GetSiteByID(ctx context.Context, siteID int64) (models.Site, e
func (s *Service) ListAllSitesWithOwners(ctx context.Context) ([]db.SiteWithOwner, error) {
return s.db.SelectAllSitesWithOwners(ctx)
}
type UpdateSiteSettingsParams struct {
SiteID int64 `form:"siteID"`
Name string `form:"name"`
Tagline string `form:"tagline"`
Timezone string `form:"timezone"`
}
func (s *Service) UpdateSiteSettings(ctx context.Context, params UpdateSiteSettingsParams) (models.Site, error) {
site, err := s.GetSiteByID(ctx, params.SiteID)
if err != nil {
return models.Site{}, err
}
_, err = time.LoadLocation(params.Timezone)
if err != nil {
return models.Site{}, errors.Wrap(err, "invalid timezone")
}
site.Title = params.Name
site.Tagline = params.Tagline
site.Timezone = params.Timezone
if err := s.db.SaveSite(ctx, &site); err != nil {
return models.Site{}, err
}
return site, nil
}

23
services/sites/tzones.go Normal file
View file

@ -0,0 +1,23 @@
package sites
import (
"embed"
"strings"
"sync"
)
//go:embed tzones.txt
var tzonesFS embed.FS
var loadZones = sync.OnceValue(func() []string {
zones, err := tzonesFS.ReadFile("tzones.txt")
if err != nil {
return nil
}
return strings.Split(string(zones), "\n")
})
func ListZones() []string {
return loadZones()
}

606
services/sites/tzones.txt Normal file
View file

@ -0,0 +1,606 @@
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Asmera
Africa/Bamako
Africa/Bangui
Africa/Banjul
Africa/Bissau
Africa/Blantyre
Africa/Brazzaville
Africa/Bujumbura
Africa/Cairo
Africa/Casablanca
Africa/Ceuta
Africa/Conakry
Africa/Dakar
Africa/Dar_es_Salaam
Africa/Djibouti
Africa/Douala
Africa/El_Aaiun
Africa/Freetown
Africa/Gaborone
Africa/Harare
Africa/Johannesburg
Africa/Juba
Africa/Kampala
Africa/Khartoum
Africa/Kigali
Africa/Kinshasa
Africa/Lagos
Africa/Libreville
Africa/Lome
Africa/Luanda
Africa/Lubumbashi
Africa/Lusaka
Africa/Malabo
Africa/Maputo
Africa/Maseru
Africa/Mbabane
Africa/Mogadishu
Africa/Monrovia
Africa/Nairobi
Africa/Ndjamena
Africa/Niamey
Africa/Nouakchott
Africa/Ouagadougou
Africa/Porto-Novo
Africa/Sao_Tome
Africa/Timbuktu
Africa/Tripoli
Africa/Tunis
Africa/Windhoek
America/Adak
America/Anchorage
America/Anguilla
America/Antigua
America/Araguaina
America/Argentina/Buenos_Aires
America/Argentina/Catamarca
America/Argentina/ComodRivadavia
America/Argentina/Cordoba
America/Argentina/Jujuy
America/Argentina/La_Rioja
America/Argentina/Mendoza
America/Argentina/Rio_Gallegos
America/Argentina/Salta
America/Argentina/San_Juan
America/Argentina/San_Luis
America/Argentina/Tucuman
America/Argentina/Ushuaia
America/Aruba
America/Asuncion
America/Atikokan
America/Atka
America/Bahia
America/Bahia_Banderas
America/Barbados
America/Belem
America/Belize
America/Blanc-Sablon
America/Boa_Vista
America/Bogota
America/Boise
America/Buenos_Aires
America/Cambridge_Bay
America/Campo_Grande
America/Cancun
America/Caracas
America/Catamarca
America/Cayenne
America/Cayman
America/Chicago
America/Chihuahua
America/Coral_Harbour
America/Cordoba
America/Costa_Rica
America/Creston
America/Cuiaba
America/Curacao
America/Danmarkshavn
America/Dawson
America/Dawson_Creek
America/Denver
America/Detroit
America/Dominica
America/Edmonton
America/Eirunepe
America/El_Salvador
America/Ensenada
America/Fort_Nelson
America/Fort_Wayne
America/Fortaleza
America/Glace_Bay
America/Godthab
America/Goose_Bay
America/Grand_Turk
America/Grenada
America/Guadeloupe
America/Guatemala
America/Guayaquil
America/Guyana
America/Halifax
America/Havana
America/Hermosillo
America/Indiana/Indianapolis
America/Indiana/Knox
America/Indiana/Marengo
America/Indiana/Petersburg
America/Indiana/Tell_City
America/Indiana/Vevay
America/Indiana/Vincennes
America/Indiana/Winamac
America/Indianapolis
America/Inuvik
America/Iqaluit
America/Jamaica
America/Jujuy
America/Juneau
America/Kentucky/Louisville
America/Kentucky/Monticello
America/Knox_IN
America/Kralendijk
America/La_Paz
America/Lima
America/Los_Angeles
America/Louisville
America/Lower_Princes
America/Maceio
America/Managua
America/Manaus
America/Marigot
America/Martinique
America/Matamoros
America/Mazatlan
America/Mendoza
America/Menominee
America/Merida
America/Metlakatla
America/Mexico_City
America/Miquelon
America/Moncton
America/Monterrey
America/Montevideo
America/Montreal
America/Montserrat
America/Nassau
America/New_York
America/Nipigon
America/Nome
America/Noronha
America/North_Dakota/Beulah
America/North_Dakota/Center
America/North_Dakota/New_Salem
America/Ojinaga
America/Panama
America/Pangnirtung
America/Paramaribo
America/Phoenix
America/Port-au-Prince
America/Port_of_Spain
America/Porto_Acre
America/Porto_Velho
America/Puerto_Rico
America/Punta_Arenas
America/Rainy_River
America/Rankin_Inlet
America/Recife
America/Regina
America/Resolute
America/Rio_Branco
America/Rosario
America/Santa_Isabel
America/Santarem
America/Santiago
America/Santo_Domingo
America/Sao_Paulo
America/Scoresbysund
America/Shiprock
America/Sitka
America/St_Barthelemy
America/St_Johns
America/St_Kitts
America/St_Lucia
America/St_Thomas
America/St_Vincent
America/Swift_Current
America/Tegucigalpa
America/Thule
America/Thunder_Bay
America/Tijuana
America/Toronto
America/Tortola
America/Vancouver
America/Virgin
America/Whitehorse
America/Winnipeg
America/Yakutat
America/Yellowknife
Antarctica/Casey
Antarctica/Davis
Antarctica/DumontDUrville
Antarctica/Macquarie
Antarctica/Mawson
Antarctica/McMurdo
Antarctica/Palmer
Antarctica/Rothera
Antarctica/South_Pole
Antarctica/Syowa
Antarctica/Troll
Antarctica/Vostok
Arctic/Longyearbyen
Asia/Aden
Asia/Almaty
Asia/Amman
Asia/Anadyr
Asia/Aqtau
Asia/Aqtobe
Asia/Ashgabat
Asia/Ashkhabad
Asia/Atyrau
Asia/Baghdad
Asia/Bahrain
Asia/Baku
Asia/Bangkok
Asia/Barnaul
Asia/Beirut
Asia/Bishkek
Asia/Brunei
Asia/Calcutta
Asia/Chita
Asia/Choibalsan
Asia/Chongqing
Asia/Chungking
Asia/Colombo
Asia/Dacca
Asia/Damascus
Asia/Dhaka
Asia/Dili
Asia/Dubai
Asia/Dushanbe
Asia/Famagusta
Asia/Gaza
Asia/Harbin
Asia/Hebron
Asia/Ho_Chi_Minh
Asia/Hong_Kong
Asia/Hovd
Asia/Irkutsk
Asia/Istanbul
Asia/Jakarta
Asia/Jayapura
Asia/Jerusalem
Asia/Kabul
Asia/Kamchatka
Asia/Karachi
Asia/Kashgar
Asia/Kathmandu
Asia/Katmandu
Asia/Khandyga
Asia/Kolkata
Asia/Krasnoyarsk
Asia/Kuala_Lumpur
Asia/Kuching
Asia/Kuwait
Asia/Macao
Asia/Macau
Asia/Magadan
Asia/Makassar
Asia/Manila
Asia/Muscat
Asia/Nicosia
Asia/Novokuznetsk
Asia/Novosibirsk
Asia/Omsk
Asia/Oral
Asia/Phnom_Penh
Asia/Pontianak
Asia/Pyongyang
Asia/Qatar
Asia/Qyzylorda
Asia/Rangoon
Asia/Riyadh
Asia/Saigon
Asia/Sakhalin
Asia/Samarkand
Asia/Seoul
Asia/Shanghai
Asia/Singapore
Asia/Srednekolymsk
Asia/Taipei
Asia/Tashkent
Asia/Tbilisi
Asia/Tehran
Asia/Tel_Aviv
Asia/Thimbu
Asia/Thimphu
Asia/Tokyo
Asia/Tomsk
Asia/Ujung_Pandang
Asia/Ulaanbaatar
Asia/Ulan_Bator
Asia/Urumqi
Asia/Ust-Nera
Asia/Vientiane
Asia/Vladivostok
Asia/Yakutsk
Asia/Yangon
Asia/Yekaterinburg
Asia/Yerevan
Atlantic/Azores
Atlantic/Bermuda
Atlantic/Canary
Atlantic/Cape_Verde
Atlantic/Faeroe
Atlantic/Faroe
Atlantic/Jan_Mayen
Atlantic/Madeira
Atlantic/Reykjavik
Atlantic/South_Georgia
Atlantic/St_Helena
Atlantic/Stanley
Australia/ACT
Australia/Adelaide
Australia/Brisbane
Australia/Broken_Hill
Australia/Canberra
Australia/Currie
Australia/Darwin
Australia/Eucla
Australia/Hobart
Australia/LHI
Australia/Lindeman
Australia/Lord_Howe
Australia/Melbourne
Australia/NSW
Australia/North
Australia/Perth
Australia/Queensland
Australia/South
Australia/Sydney
Australia/Tasmania
Australia/Victoria
Australia/West
Australia/Yancowinna
Brazil/Acre
Brazil/DeNoronha
Brazil/East
Brazil/West
CET
CST6CDT
Canada/Atlantic
Canada/Central
Canada/Eastern
Canada/Mountain
Canada/Newfoundland
Canada/Pacific
Canada/Saskatchewan
Canada/Yukon
Chile/Continental
Chile/EasterIsland
Cuba
EET
EST
EST5EDT
Egypt
Eire
Etc/GMT
Etc/GMT+0
Etc/GMT+1
Etc/GMT+10
Etc/GMT+11
Etc/GMT+12
Etc/GMT+2
Etc/GMT+3
Etc/GMT+4
Etc/GMT+5
Etc/GMT+6
Etc/GMT+7
Etc/GMT+8
Etc/GMT+9
Etc/GMT-0
Etc/GMT-1
Etc/GMT-10
Etc/GMT-11
Etc/GMT-12
Etc/GMT-13
Etc/GMT-14
Etc/GMT-2
Etc/GMT-3
Etc/GMT-4
Etc/GMT-5
Etc/GMT-6
Etc/GMT-7
Etc/GMT-8
Etc/GMT-9
Etc/GMT0
Etc/Greenwich
Etc/UCT
Etc/UTC
Etc/Universal
Etc/Zulu
Europe/Amsterdam
Europe/Andorra
Europe/Astrakhan
Europe/Athens
Europe/Belfast
Europe/Belgrade
Europe/Berlin
Europe/Bratislava
Europe/Brussels
Europe/Bucharest
Europe/Budapest
Europe/Busingen
Europe/Chisinau
Europe/Copenhagen
Europe/Dublin
Europe/Gibraltar
Europe/Guernsey
Europe/Helsinki
Europe/Isle_of_Man
Europe/Istanbul
Europe/Jersey
Europe/Kaliningrad
Europe/Kiev
Europe/Kirov
Europe/Lisbon
Europe/Ljubljana
Europe/London
Europe/Luxembourg
Europe/Madrid
Europe/Malta
Europe/Mariehamn
Europe/Minsk
Europe/Monaco
Europe/Moscow
Europe/Nicosia
Europe/Oslo
Europe/Paris
Europe/Podgorica
Europe/Prague
Europe/Riga
Europe/Rome
Europe/Samara
Europe/San_Marino
Europe/Sarajevo
Europe/Saratov
Europe/Simferopol
Europe/Skopje
Europe/Sofia
Europe/Stockholm
Europe/Tallinn
Europe/Tirane
Europe/Tiraspol
Europe/Ulyanovsk
Europe/Uzhgorod
Europe/Vaduz
Europe/Vatican
Europe/Vienna
Europe/Vilnius
Europe/Volgograd
Europe/Warsaw
Europe/Zagreb
Europe/Zaporozhye
Europe/Zurich
Factory
GB
GB-Eire
GMT
GMT+0
GMT-0
GMT0
Greenwich
HST
Hongkong
Iceland
Indian/Antananarivo
Indian/Chagos
Indian/Christmas
Indian/Cocos
Indian/Comoro
Indian/Kerguelen
Indian/Mahe
Indian/Maldives
Indian/Mauritius
Indian/Mayotte
Indian/Reunion
Iran
Israel
Jamaica
Japan
Kwajalein
Libya
MET
MST
MST7MDT
Mexico/BajaNorte
Mexico/BajaSur
Mexico/General
NZ
NZ-CHAT
Navajo
PRC
PST8PDT
Pacific/Apia
Pacific/Auckland
Pacific/Bougainville
Pacific/Chatham
Pacific/Chuuk
Pacific/Easter
Pacific/Efate
Pacific/Enderbury
Pacific/Fakaofo
Pacific/Fiji
Pacific/Funafuti
Pacific/Galapagos
Pacific/Gambier
Pacific/Guadalcanal
Pacific/Guam
Pacific/Honolulu
Pacific/Johnston
Pacific/Kiritimati
Pacific/Kosrae
Pacific/Kwajalein
Pacific/Majuro
Pacific/Marquesas
Pacific/Midway
Pacific/Nauru
Pacific/Niue
Pacific/Norfolk
Pacific/Noumea
Pacific/Pago_Pago
Pacific/Palau
Pacific/Pitcairn
Pacific/Pohnpei
Pacific/Ponape
Pacific/Port_Moresby
Pacific/Rarotonga
Pacific/Saipan
Pacific/Samoa
Pacific/Tahiti
Pacific/Tarawa
Pacific/Tongatapu
Pacific/Truk
Pacific/Wake
Pacific/Wallis
Pacific/Yap
Poland
Portugal
ROC
ROK
Singapore
SystemV/AST4
SystemV/AST4ADT
SystemV/CST6
SystemV/CST6CDT
SystemV/EST5
SystemV/EST5EDT
SystemV/HST10
SystemV/MST7
SystemV/MST7MDT
SystemV/PST8
SystemV/PST8PDT
SystemV/YST9
SystemV/YST9YDT
Turkey
UCT
US/Alaska
US/Aleutian
US/Arizona
US/Central
US/East-Indiana
US/Eastern
US/Hawaii
US/Indiana-Starke
US/Michigan
US/Mountain
US/Pacific
US/Pacific-New
US/Samoa
UTC
Universal
W-SU
WET
Zulu

View file

@ -13,13 +13,17 @@ INSERT INTO sites (
guid,
title,
tagline,
timezone,
created_at
) VALUES (?, ?, ?, ?, ?)
) VALUES (?, ?, ?, ?, ?, ?)
RETURNING id;
-- name: HasUsersAndSites :one
SELECT (SELECT COUNT(*) FROM users) > 0 AND (SELECT COUNT(*) FROM sites) > 0 AS has_users_and_sites;
-- name: UpdateSite :exec
UPDATE sites SET title = ?, tagline = ?, timezone = ? WHERE id = ?;
-- name: SelectAllSitesWithOwners :many
SELECT s.id, s.guid, s.title, s.owner_id, u.username
FROM sites s

View file

@ -0,0 +1 @@
ALTER TABLE sites ADD COLUMN timezone TEXT NOT NULL DEFAULT 'UTC';

View file

@ -13,6 +13,9 @@
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="/sites/{{.site.ID}}/uploads">Uploads</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="/sites/{{.site.ID}}/settings">Settings</a>
</li>
</ul>
<form class="d-flex align-items-center" role="search">
<!--

View file

@ -3,9 +3,6 @@
<div class="my-4 d-flex justify-content-between align-items-baseline">
<div>
<a href="/sites/{{ .site.ID }}/posts/new" class="btn btn-success">New Post</a>
<form action="/sites/{{ .site.ID }}/rebuild" method="post" style="display: inline-block;">
<input type="submit" class="btn btn-outline-primary" value="Rebuild Site">
</form>
</div>
<div>

View file

@ -0,0 +1,63 @@
<main class="container">
<!--
<ul class="nav nav-pills justify-content-center my-3">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">General</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Feeds</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Publish</a>
</li>
</ul>
-->
<div>
<form method="post" action="/sites/{{ .site.ID }}/settings">
<div>
<h5 class="my-4">Site Settings</h5>
</div>
<div class="row mb-3">
<label for="siteName" class="col-sm-3 col-form-label text-end">Site Name</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="siteName" name="name" value="{{ .site.Title }}">
</div>
</div>
<div class="row mb-3">
<label for="siteTagline" class="col-sm-3 col-form-label text-end">Site Tagline</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="siteTagline" name="tagline" value="{{ .site.Tagline }}">
</div>
</div>
<div class="row mb-3">
<label for="timezone" class="col-sm-3 col-form-label text-end">Timezone</label>
<div class="col-sm-6">
<input type="text" list="tzoneList" class="form-control" id="timezone" name="timezone" value="{{ .site.Timezone }}">
<datalist id="tzoneList">
{{ range .tzones }}
<option value="{{ . }}">{{ . }}</option>
{{ end }}
</datalist>
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3"></div>
<div class="col-sm-9"><button type="submit" class="btn btn-primary">Save Settings</button></div>
</div>
</form>
<hr>
<div>
<h5 class="my-4">Manage</h5>
</div>
<form action="/sites/{{ .site.ID }}/rebuild" method="post">
<div class="row mb-3">
<div class="col-sm-3"></div>
<div class="col-sm-9">
<button type="submit" class="btn btn-secondary">Rebuild</button>
<span class="form-text mx-3">Trigger a full rebuild of the site.</span>
</div>
</div>
</form>
</div>
</main>