diff --git a/go.mod b/go.mod index 3fee4a9..c6e73c1 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( github.com/gofiber/template/v2 v2.1.0 // indirect github.com/gofiber/utils/v2 v2.0.2 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.18.4 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect @@ -65,6 +66,8 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rsc/goversion v1.2.0 // indirect github.com/sirupsen/logrus v1.6.0 // indirect + github.com/spf13/cobra v1.10.2 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/tinylib/msgp v1.6.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.69.0 // indirect diff --git a/go.sum b/go.sum index cd657c5..6f783dd 100644 --- a/go.sum +++ b/go.sum @@ -73,6 +73,7 @@ github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -295,6 +296,8 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -408,6 +411,7 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rsc/goversion v1.2.0 h1:zVF4y5ciA/rw779S62bEAq4Yif1cBc/UwRkXJ2xZyT4= github.com/rsc/goversion v1.2.0/go.mod h1:Tf/O0TQyfRvp7NelXAyfXYRKUO+LX3KNgXc8ALRUv4k= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -426,10 +430,15 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -480,6 +489,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/models/ids.go b/models/ids.go index 58dd928..c5c1cbd 100644 --- a/models/ids.go +++ b/models/ids.go @@ -3,6 +3,6 @@ package models import "github.com/matoous/go-nanoid/v2" func NewNanoID() string { - id, _ := gonanoid.New(12) + id, _ := gonanoid.New(16) return id } diff --git a/models/sites.go b/models/sites.go index 3b2a6f4..c56c0f4 100644 --- a/models/sites.go +++ b/models/sites.go @@ -13,6 +13,7 @@ const ( type Site struct { ID int64 OwnerID int64 + GUID string Created time.Time Title string @@ -29,24 +30,3 @@ type SitePublishTarget struct { TargetRef string TargetKey string } - -/* -type SiteMeta struct { - Title string `yaml:"title"` - Tagline string `yaml:"tagline"` - BaseURL string `yaml:"base_url"` -} - -type PostMeta struct { - ID string `yaml:"id"` - Title string `yaml:"title"` - Date time.Time `yaml:"date"` - Tags []string `yaml:"tags"` - Slug string `yaml:"slug"` -} - -type Post struct { - Meta PostMeta - Content string -} -*/ diff --git a/providers/db/gen/sqlgen/models.go b/providers/db/gen/sqlgen/models.go index dd9aa92..f991778 100644 --- a/providers/db/gen/sqlgen/models.go +++ b/providers/db/gen/sqlgen/models.go @@ -31,6 +31,7 @@ type PublishTarget struct { type Site struct { ID int64 OwnerID int64 + Guid string Title string Tagline string CreatedAt int64 diff --git a/providers/db/gen/sqlgen/sites.sql.go b/providers/db/gen/sqlgen/sites.sql.go index e939bfb..90b7000 100644 --- a/providers/db/gen/sqlgen/sites.sql.go +++ b/providers/db/gen/sqlgen/sites.sql.go @@ -24,15 +24,17 @@ func (q *Queries) HasUsersAndSites(ctx context.Context) (sql.NullBool, error) { const insertSite = `-- name: InsertSite :one INSERT INTO sites ( owner_id, + guid, title, tagline, created_at -) VALUES (?, ?, ?, ?) +) VALUES (?, ?, ?, ?, ?) RETURNING id ` type InsertSiteParams struct { OwnerID int64 + Guid string Title string Tagline string CreatedAt int64 @@ -41,6 +43,7 @@ type InsertSiteParams struct { func (q *Queries) InsertSite(ctx context.Context, arg InsertSiteParams) (int64, error) { row := q.db.QueryRowContext(ctx, insertSite, arg.OwnerID, + arg.Guid, arg.Title, arg.Tagline, arg.CreatedAt, @@ -51,7 +54,7 @@ func (q *Queries) InsertSite(ctx context.Context, arg InsertSiteParams) (int64, } const selectSiteByID = `-- name: SelectSiteByID :one -SELECT id, owner_id, title, tagline, created_at FROM sites WHERE id = ? +SELECT id, owner_id, guid, title, tagline, created_at FROM sites WHERE id = ? ` func (q *Queries) SelectSiteByID(ctx context.Context, id int64) (Site, error) { @@ -60,6 +63,7 @@ func (q *Queries) SelectSiteByID(ctx context.Context, id int64) (Site, error) { err := row.Scan( &i.ID, &i.OwnerID, + &i.Guid, &i.Title, &i.Tagline, &i.CreatedAt, @@ -68,7 +72,7 @@ func (q *Queries) SelectSiteByID(ctx context.Context, id int64) (Site, error) { } const selectSitesOwnedByUser = `-- name: SelectSitesOwnedByUser :many -SELECT id, owner_id, title, tagline, created_at FROM sites WHERE owner_id = ? ORDER BY title ASC +SELECT id, owner_id, guid, title, tagline, created_at FROM sites WHERE owner_id = ? ORDER BY title ASC ` func (q *Queries) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ([]Site, error) { @@ -83,6 +87,7 @@ func (q *Queries) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ([] if err := rows.Scan( &i.ID, &i.OwnerID, + &i.Guid, &i.Title, &i.Tagline, &i.CreatedAt, diff --git a/providers/db/sites.go b/providers/db/sites.go index 8336248..51fc17f 100644 --- a/providers/db/sites.go +++ b/providers/db/sites.go @@ -14,13 +14,7 @@ func (db *Provider) SelectSiteByID(ctx context.Context, id int64) (models.Site, return models.Site{}, err } - return models.Site{ - ID: row.ID, - OwnerID: row.OwnerID, - Title: row.Title, - Tagline: row.Tagline, - Created: time.Unix(row.CreatedAt, 0).UTC(), - }, nil + return dbSiteToSite(row), nil } func (db *Provider) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ([]models.Site, error) { @@ -31,13 +25,7 @@ func (db *Provider) SelectSitesOwnedByUser(ctx context.Context, ownerID int64) ( sites := make([]models.Site, len(rows)) for i, row := range rows { - sites[i] = models.Site{ - ID: row.ID, - OwnerID: row.OwnerID, - Title: row.Title, - Tagline: row.Tagline, - Created: time.Unix(row.CreatedAt, 0).UTC(), - } + sites[i] = dbSiteToSite(row) } return sites, nil } @@ -46,6 +34,7 @@ func (db *Provider) SaveSite(ctx context.Context, site *models.Site) error { if site.ID == 0 { newID, err := db.queries.InsertSite(ctx, sqlgen.InsertSiteParams{ OwnerID: site.OwnerID, + Guid: site.GUID, Title: site.Title, Tagline: site.Tagline, CreatedAt: timeToInt(site.Created), @@ -68,3 +57,14 @@ func (db *Provider) HasUsersAndSites(ctx context.Context) (bool, error) { } return nullBool.Valid && nullBool.Bool, nil } + +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(), + } +} diff --git a/services/sites/services.go b/services/sites/services.go index 7bb6818..d3711c9 100644 --- a/services/sites/services.go +++ b/services/sites/services.go @@ -77,6 +77,7 @@ 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(), } diff --git a/sql/queries/sites.sql b/sql/queries/sites.sql index 5632928..682aaaf 100644 --- a/sql/queries/sites.sql +++ b/sql/queries/sites.sql @@ -7,10 +7,11 @@ SELECT * FROM sites WHERE id = ?; -- name: InsertSite :one INSERT INTO sites ( owner_id, + guid, title, tagline, created_at -) VALUES (?, ?, ?, ?) +) VALUES (?, ?, ?, ?, ?) RETURNING id; -- name: HasUsersAndSites :one diff --git a/sql/schema/01_init.up.sql b/sql/schema/01_init.up.sql index 22d3e60..3bfce69 100644 --- a/sql/schema/01_init.up.sql +++ b/sql/schema/01_init.up.sql @@ -9,6 +9,7 @@ CREATE UNIQUE INDEX idx_users_username ON users (username); CREATE TABLE sites ( id INTEGER PRIMARY KEY AUTOINCREMENT, owner_id INTEGER NOT NULL, + guid TEXT NOT NULL, title TEXT NOT NULL, tagline TEXT NOT NULL, created_at INTEGER NOT NULL, @@ -16,6 +17,7 @@ CREATE TABLE sites ( FOREIGN KEY (owner_id) REFERENCES users (id) ON DELETE CASCADE ); CREATE INDEX idx_site_owner ON sites (owner_id); +CREATE UNIQUE INDEX idx_site_guid ON sites (guid); CREATE TABLE publish_targets ( id INTEGER PRIMARY KEY AUTOINCREMENT, diff --git a/views/layouts/main.html b/views/layouts/main.html index 0480166..2b81177 100644 --- a/views/layouts/main.html +++ b/views/layouts/main.html @@ -2,7 +2,7 @@
-