An experimental IndieWeb site built in Go.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

migrate from CloverDB to SQLite

First step in adopting Litestream for DB replication

+375 -380
+20 -34
db/storage.go
··· 2 2 3 3 import ( 4 4 "log" 5 + "os" 6 + "path/filepath" 5 7 "time" 8 + 9 + "github.com/puregarlic/space/models" 6 10 7 11 "github.com/jellydator/ttlcache/v3" 8 - "github.com/ostafen/clover/v2" 9 12 "go.hacdias.com/indielib/indieauth" 13 + 14 + "github.com/glebarez/sqlite" 15 + "gorm.io/gorm" 10 16 ) 11 17 12 18 type Storage struct { 13 - Docs *clover.DB 19 + Db *gorm.DB 14 20 Authorization *ttlcache.Cache[string, *indieauth.AuthenticationRequest] 15 21 } 16 22 ··· 21 27 ) 22 28 23 29 func NewStorage() *Storage { 24 - c, err := clover.Open("data/docs") 30 + dataDir := filepath.Join(".", "data") 31 + if err := os.MkdirAll(dataDir, os.ModePerm); err != nil { 32 + log.Fatal(err) 33 + } 34 + 35 + db, err := gorm.Open(sqlite.Open(filepath.Join(dataDir, "data.db")), &gorm.Config{}) 25 36 if err != nil { 26 37 log.Fatal(err) 38 + } 39 + 40 + if err := db.AutoMigrate(&models.Post{}); err != nil { 41 + panic(err) 27 42 } 28 43 29 44 cache := ttlcache.New[string, *indieauth.AuthenticationRequest]( ··· 33 48 go cache.Start() 34 49 35 50 store := &Storage{ 36 - Docs: c, 51 + // Docs: c, 52 + Db: db, 37 53 Authorization: cache, 38 54 } 39 55 40 - store.SetupClover() 41 - 42 56 return store 43 57 } 44 58 45 - func (db *Storage) SetupClover() { 46 - if ok, err := db.Docs.HasCollection(string(PostCollection)); err != nil { 47 - panic(err) 48 - } else if !ok { 49 - err := db.Docs.CreateCollection(string(PostCollection)) 50 - if err != nil { 51 - panic(err) 52 - } 53 - } 54 - 55 - if ok, err := db.Docs.HasIndex(string(PostCollection), "createdAt"); err != nil { 56 - panic(err) 57 - } else if !ok { 58 - err := db.Docs.CreateIndex(string(PostCollection), "createdAt") 59 - if err != nil { 60 - panic(err) 61 - } 62 - } 63 - } 64 - 65 59 func (db *Storage) Cleanup() { 66 - if err := db.Docs.Close(); err != nil { 67 - panic(err) 68 - } 69 - 70 60 db.Authorization.Stop() 71 61 } 72 - 73 - func (db *Storage) SetupTokenCache() { 74 - 75 - }
+18 -20
go.mod
··· 3 3 go 1.22.5 4 4 5 5 require ( 6 + codeberg.org/gruf/go-ulid v1.1.0 6 7 github.com/aidarkhanov/nanoid v1.0.8 8 + github.com/glebarez/sqlite v1.11.0 7 9 github.com/jellydator/ttlcache/v3 v3.2.0 8 10 github.com/joho/godotenv v1.5.1 9 - github.com/ostafen/clover/v2 v2.0.0-alpha.3 10 11 go.hacdias.com/indielib v0.3.1 12 + gorm.io/datatypes v1.2.1 13 + gorm.io/gorm v1.25.11 11 14 ) 12 15 13 16 require ( 14 - github.com/cespare/xxhash v1.1.0 // indirect 17 + filippo.io/edwards25519 v1.1.0 // indirect 15 18 github.com/cespare/xxhash/v2 v2.3.0 // indirect 16 - github.com/dgraph-io/badger/v3 v3.2103.2 // indirect 17 - github.com/dgraph-io/ristretto v0.1.0 // indirect 18 - github.com/dustin/go-humanize v1.0.0 // indirect 19 - github.com/gogo/protobuf v1.3.2 // indirect 20 - github.com/golang/glog v1.0.0 // indirect 21 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 22 - github.com/golang/protobuf v1.5.2 // indirect 23 - github.com/golang/snappy v0.0.4 // indirect 24 - github.com/google/flatbuffers v2.0.6+incompatible // indirect 25 - github.com/google/orderedcode v0.0.1 // indirect 26 - github.com/klauspost/compress v1.15.9 // indirect 27 - github.com/pkg/errors v0.9.1 // indirect 28 - github.com/satori/go.uuid v1.2.0 // indirect 29 - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect 30 - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 31 - go.etcd.io/bbolt v1.3.6 // indirect 32 - go.opencensus.io v0.23.0 // indirect 19 + github.com/dustin/go-humanize v1.0.1 // indirect 20 + github.com/glebarez/go-sqlite v1.21.2 // indirect 21 + github.com/go-sql-driver/mysql v1.8.1 // indirect 22 + github.com/google/uuid v1.3.0 // indirect 23 + github.com/jinzhu/inflection v1.0.0 // indirect 24 + github.com/jinzhu/now v1.1.5 // indirect 25 + github.com/mattn/go-isatty v0.0.20 // indirect 26 + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 33 27 golang.org/x/sync v0.7.0 // indirect 34 28 golang.org/x/sys v0.22.0 // indirect 35 29 golang.org/x/text v0.16.0 // indirect 36 - google.golang.org/protobuf v1.28.1 // indirect 30 + gorm.io/driver/mysql v1.5.6 // indirect 31 + modernc.org/libc v1.22.5 // indirect 32 + modernc.org/mathutil v1.5.0 // indirect 33 + modernc.org/memory v1.5.0 // indirect 34 + modernc.org/sqlite v1.23.1 // indirect 37 35 ) 38 36 39 37 require (
+66 -208
go.sum
··· 1 - cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 - github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 - github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= 4 - github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 1 + codeberg.org/gruf/go-ulid v1.1.0 h1:run+0r3hQqF1G7Am1oAt/msoK+FPKnlcQ6sc/biXWqw= 2 + codeberg.org/gruf/go-ulid v1.1.0/go.mod h1:dVNsZJpVTge8+jfBTjAMpnscYSiCqk+g32ZgtorCAMs= 3 + filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 4 + filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 5 5 github.com/a-h/templ v0.2.747 h1:D0dQ2lxC3W7Dxl6fxQ/1zZHBQslSkTSvl5FxP/CfdKg= 6 6 github.com/a-h/templ v0.2.747/go.mod h1:69ObQIbrcuwPCU32ohNaWce3Cb7qM5GMiqN1K+2yop4= 7 7 github.com/aidarkhanov/nanoid v1.0.8 h1:yxyJkgsEDFXP7+97vc6JevMcjyb03Zw+/9fqhlVXBXA= 8 8 github.com/aidarkhanov/nanoid v1.0.8/go.mod h1:vadfZHT+m4uDhttg0yY4wW3GKtl2T6i4d2Age+45pYk= 9 9 github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= 10 - github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 11 - github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4= 12 - github.com/brianvoe/gofakeit/v6 v6.17.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= 13 - github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 14 - github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 15 - github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 16 - github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 17 - github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 18 10 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 19 11 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 20 - github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 21 - github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 22 - github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 23 - github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 24 - github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 25 - github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 26 - github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 27 12 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 28 13 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 29 - github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8= 30 - github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= 31 - github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= 32 - github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= 33 - github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= 34 - github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= 35 - github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= 36 - github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 37 - github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 38 - github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 39 - github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 40 - github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 41 - github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 14 + github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 15 + github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 16 + github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= 17 + github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= 18 + github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= 19 + github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= 42 20 github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= 43 21 github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 44 22 github.com/go-chi/httprate v0.12.0 h1:08D/te3pOTJe5+VAZTQrHxwdsH2NyliiUoRD1naKaMg= 45 23 github.com/go-chi/httprate v0.12.0/go.mod h1:TUepLXaz/pCjmCtf/obgOQJ2Sz6rC8fSf5cAt5cnTt0= 46 - github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 47 - github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 24 + github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 25 + github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= 26 + github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= 48 27 github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= 49 28 github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 50 - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 51 - github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= 52 - github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= 53 - github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 54 - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 55 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 56 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 57 - github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 58 - github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 59 - github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 60 - github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 61 - github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 62 - github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 63 - github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 64 - github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 65 - github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 66 - github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 67 - github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 68 - github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 69 - github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 70 - github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 71 - github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 72 - github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 73 - github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 74 - github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 75 - github.com/google/flatbuffers v2.0.6+incompatible h1:XHFReMv7nFFusa+CEokzWbzaYocKXI6C7hdU5Kgh9Lw= 76 - github.com/google/flatbuffers v2.0.6+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 77 - github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 78 - github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 79 - github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 80 - github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 81 - github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 82 - github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 83 - github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 84 - github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 29 + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= 30 + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 31 + github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= 32 + github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= 85 33 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 86 34 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 87 35 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 88 - github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= 89 - github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= 90 - github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 91 - github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 92 - github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 36 + github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= 37 + github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= 38 + github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 39 + github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 40 + github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 41 + github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 42 + github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= 43 + github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 44 + github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= 45 + github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= 46 + github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= 47 + github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 93 48 github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= 94 49 github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= 50 + github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 51 + github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 52 + github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 53 + github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 95 54 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 96 55 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 97 - github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 98 - github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 99 - github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= 100 - github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= 101 - github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= 102 - github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 103 - github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= 104 - github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 105 - github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 106 - github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 107 - github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 108 - github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 109 - github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 110 - github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 111 - github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 112 - github.com/ostafen/clover/v2 v2.0.0-alpha.3 h1:fXC7tVHQkUPFlxlj/kD98h0ngrTpIeJymaxVIqDzw3Q= 113 - github.com/ostafen/clover/v2 v2.0.0-alpha.3/go.mod h1:5YCDt+wJDUNN1uSXE5csxSQBuJrNjidkOkJTXWuNhDY= 114 - github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 115 - github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 116 - github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 56 + github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 57 + github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 58 + github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= 59 + github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 60 + github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= 61 + github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= 117 62 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 118 63 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 119 - github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 120 - github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 64 + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 65 + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 66 + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 121 67 github.com/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ= 122 68 github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= 123 - github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 124 - github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 125 - github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 126 - github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 127 - github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 128 - github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 129 - github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 130 - github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 131 - github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 132 - github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 133 - github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 134 - github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 135 69 github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= 136 70 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 137 - github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 138 - github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 139 - github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 140 - github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 141 71 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 142 72 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 143 - github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 144 - github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= 145 - github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= 146 - github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= 147 - github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= 148 73 github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= 149 - github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 150 - github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 151 - github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 152 - go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= 153 - go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= 154 74 go.hacdias.com/indielib v0.3.1 h1:t6IUp2lfQBa3baXcBN9S/A4fBq4vzMWVbfCQgPcDpy8= 155 75 go.hacdias.com/indielib v0.3.1/go.mod h1:ushJ07W6LxAbZWhyqXzQQxXkalPkZo6cGz5Uj2wOdb4= 156 - go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 157 - go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= 158 - go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 159 76 go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= 160 77 go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= 161 - golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 162 - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 163 - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 164 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 165 - golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 166 - golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 167 - golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 168 - golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 169 - golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 170 - golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 171 - golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 172 - golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 173 - golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 174 - golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 175 - golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 176 - golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 177 - golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 178 - golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 179 - golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 78 + golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= 79 + golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= 180 80 golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 181 81 golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 182 - golang.org/x/net v0.0.0-20220728211354-c7608f3a8462/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 183 82 golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= 184 83 golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= 185 - golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 186 84 golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= 187 85 golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 188 - golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 189 - golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 190 - golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 191 - golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 192 - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 193 - golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 194 86 golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= 195 87 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 196 - golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 197 - golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 198 - golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 199 - golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 200 - golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 201 - golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 202 - golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 203 88 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 204 - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 205 89 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 206 - golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 207 - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 90 + golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 208 91 golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= 209 92 golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 210 93 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 211 - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 212 - golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 213 - golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 214 94 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 215 - golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 216 95 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= 217 96 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 218 97 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 219 - golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 220 - golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 221 - golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 222 - golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 223 - golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 224 - golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 225 - golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 226 - golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 227 - golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 228 98 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 229 - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 230 - google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 231 - google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 232 - google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 233 - google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 234 - google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 235 - google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 236 - google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 237 - google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 238 - google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 239 - google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 240 - google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 241 - google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 242 - google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 243 - google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 244 - google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 245 - google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 246 - google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 247 - google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 248 - google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 249 - google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 250 - google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 251 - google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 252 - google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 253 - google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 254 - google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 255 - gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 256 - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 257 - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 258 - gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 259 - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 260 99 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 261 100 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 262 - honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 263 - honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 101 + gorm.io/datatypes v1.2.1 h1:r+g0bk4LPCW2v4+Ls7aeNgGme7JYdNDQ2VtvlNUfBh0= 102 + gorm.io/datatypes v1.2.1/go.mod h1:hYK6OTb/1x+m96PgoZZq10UXJ6RvEBb9kRDQ2yyhzGs= 103 + gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= 104 + gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= 105 + gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= 106 + gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= 107 + gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= 108 + gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= 109 + gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= 110 + gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= 111 + gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= 112 + gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= 113 + gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= 114 + modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= 115 + modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= 116 + modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= 117 + modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= 118 + modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= 119 + modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= 120 + modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= 121 + modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= 264 122 willnorris.com/go/microformats v1.2.1-0.20240301064101-b5d1b9d2120e h1:TRIOwo0NxN4KVSgYlYmiQktd9I96YgZ3942/JVzhwTM= 265 123 willnorris.com/go/microformats v1.2.1-0.20240301064101-b5d1b9d2120e/go.mod h1:zzo0hFA/E/nl1ZAjXiXA7KCKwCTdgBU+7HXltGgHeGA= 266 124 willnorris.com/go/webmention v0.0.0-20220108183051-4a23794272f0 h1:V5+O+YZHchEwu6ZmPcqT1dQ+mHgE356Q+w9SVOQ+QZg=
+51 -36
main.go
··· 9 9 "net/http" 10 10 "strconv" 11 11 12 - "github.com/ostafen/clover/v2/query" 13 - 14 12 "github.com/puregarlic/space/db" 13 + "github.com/puregarlic/space/models" 15 14 "github.com/puregarlic/space/pages" 16 - "github.com/puregarlic/space/types" 17 15 18 16 "github.com/a-h/templ" 19 17 "github.com/go-chi/chi/v5" ··· 100 98 } 101 99 102 100 func (s *server) serveHomeTemplate(w http.ResponseWriter, r *http.Request) { 103 - q := query.NewQuery( 104 - string(db.PostCollection), 105 - ).Sort(query.SortOption{ 106 - Field: "createdAt", 107 - Direction: -1, 108 - }).Limit(10) 101 + // q := query.NewQuery( 102 + // string(db.PostCollection), 103 + // ).Sort(query.SortOption{ 104 + // Field: "createdAt", 105 + // Direction: -1, 106 + // }).Limit(10) 109 107 110 - docs, err := s.db.Docs.FindAll(q) 111 - if err != nil { 112 - httpError(w, http.StatusInternalServerError) 113 - panic(err) 108 + // docs, err := s.db.Docs.FindAll(q) 109 + // if err != nil { 110 + // httpError(w, http.StatusInternalServerError) 111 + // panic(err) 112 + // } 113 + 114 + posts := make([]*models.Post, 0) 115 + result := s.db.Db.Limit(10).Find(&posts) 116 + if result.Error != nil { 117 + panic(result.Error) 114 118 } 115 119 116 - posts := make([]*types.Post, len(docs)) 117 - for i, doc := range docs { 118 - id := doc.ObjectId() 119 - post := &types.Post{ 120 - ID: id, 121 - } 120 + // posts := make([]*models.Post, len(docs)) 121 + // for i, doc := range docs { 122 + // id := doc.ObjectId() 123 + // post := &models.Post{ 124 + // ID: id, 125 + // } 122 126 123 - if err := doc.Unmarshal(post); err != nil { 124 - httpError(w, http.StatusInternalServerError) 125 - panic(err) 126 - } 127 + // if err := doc.Unmarshal(post); err != nil { 128 + // httpError(w, http.StatusInternalServerError) 129 + // panic(err) 130 + // } 127 131 128 - post.ID = id 132 + // post.ID = id 129 133 130 - posts[i] = post 131 - } 134 + // posts[i] = post 135 + // } 132 136 133 137 templ.Handler(pages.Home(s.profileURL, posts)).ServeHTTP(w, r) 134 138 } 135 139 136 140 func (s *server) servePostTemplate(w http.ResponseWriter, r *http.Request) { 137 141 id := chi.URLParam(r, "slug") 138 - post := &types.Post{} 142 + post := &models.Post{} 143 + 144 + // doc, err := s.db.Docs.FindById(string(db.PostCollection), id) 145 + // if err != nil { 146 + // httpError(w, http.StatusInternalServerError) 147 + // return 148 + // } else if doc == nil { 149 + // httpError(w, http.StatusNotFound) 150 + // return 151 + // } 152 + 153 + // postUlid, err := ulid.ParseString(id) 154 + // if err != nil { 155 + // panic(err) 156 + // } 157 + result := s.db.Db.First(post, "id = ?", id) 139 158 140 - doc, err := s.db.Docs.FindById(string(db.PostCollection), id) 141 - if err != nil { 142 - httpError(w, http.StatusInternalServerError) 143 - return 144 - } else if doc == nil { 159 + if result.RowsAffected == 0 { 145 160 httpError(w, http.StatusNotFound) 146 161 return 147 162 } 148 163 149 - if err := doc.Unmarshal(post); err != nil { 150 - httpError(w, http.StatusInternalServerError) 151 - return 152 - } 164 + // if err := doc.Unmarshal(post); err != nil { 165 + // httpError(w, http.StatusInternalServerError) 166 + // return 167 + // } 153 168 154 169 templ.Handler(pages.Post(post)).ServeHTTP(w, r) 155 170 }
+65 -48
micropub.go
··· 1 1 package main 2 2 3 3 import ( 4 + "encoding/json" 4 5 "errors" 5 6 "fmt" 6 7 "net/http" 7 8 urlpkg "net/url" 8 9 "reflect" 9 10 "strings" 10 - "time" 11 11 12 - "github.com/ostafen/clover/v2/document" 13 - "github.com/puregarlic/space/db" 14 - "github.com/puregarlic/space/types" 12 + "github.com/puregarlic/space/models" 15 13 "github.com/samber/lo" 16 14 17 15 "go.hacdias.com/indielib/micropub" ··· 45 43 } 46 44 47 45 id := postIdFromUrlPath(url.Path) 48 - post := &types.Post{} 49 - doc, err := s.server.db.Docs.FindById(string(db.PostCollection), id) 50 - if err != nil { 51 - panic(err) 52 - } else if doc == nil { 46 + post := &models.Post{} 47 + 48 + res := s.server.db.Db.Find(post, "id = ?", id) 49 + if res.Error != nil { 50 + panic(res.Error) 51 + } else if res.RowsAffected == 0 { 53 52 return nil, micropub.ErrNotFound 54 - } 55 - 56 - if err := doc.Unmarshal(post); err != nil { 57 - panic(err) 58 53 } 59 54 60 55 return map[string]any{ ··· 68 63 } 69 64 70 65 func (s *micropubImplementation) Create(req *micropub.Request) (string, error) { 71 - post := types.Post{ 66 + props, err := json.Marshal(req.Properties) 67 + if err != nil { 68 + return "", err 69 + } 70 + 71 + post := &models.Post{ 72 + ID: models.NewULID(), 72 73 Type: req.Type, 73 - Properties: req.Properties, 74 - CreatedAt: time.Now().Unix(), 75 - } 76 - doc := document.NewDocumentOf(post) 77 - if doc == nil { 78 - return "", errors.New("Could not marshal post to Clover document") 74 + Properties: props, 79 75 } 80 76 81 - id, err := s.server.db.Docs.InsertOne(string(db.PostCollection), doc) 82 - if err != nil { 83 - return "", err 77 + res := s.server.db.Db.Create(post) 78 + if res.Error != nil { 79 + return "", res.Error 84 80 } 85 81 86 - return s.profileURL + "posts/" + id, nil 82 + return s.profileURL + "posts/" + post.ID.String(), nil 87 83 } 88 84 89 85 func (s *micropubImplementation) Update(req *micropub.Request) (string, error) { ··· 93 89 } 94 90 95 91 id := postIdFromUrlPath(url.Path) 92 + post := &models.Post{} 96 93 97 - if err := s.server.db.Docs.UpdateById( 98 - string(db.PostCollection), 99 - id, 100 - func(doc *document.Document) *document.Document { 101 - post := &types.Post{} 102 - if err := doc.Unmarshal(post); err != nil { 103 - panic(err) 104 - } 94 + res := s.server.db.Db.Find(post, "id = ?", id) 95 + if res.Error != nil { 96 + panic(res.Error) 97 + } else if res.RowsAffected != 1 { 98 + return "", micropub.ErrNotFound 99 + } 105 100 106 - props, err := updateProperties(post.Properties, req) 107 - if err != nil { 108 - panic(err) 109 - } 101 + newProps, err := updateProperties(json.RawMessage(post.Properties), req) 102 + if err != nil { 103 + panic(err) 104 + } 110 105 111 - doc.Set("properties", props) 106 + post.Properties = newProps 112 107 113 - return doc 114 - }, 115 - ); err != nil { 116 - return "", fmt.Errorf("%w: %w", micropub.ErrBadRequest, err) 117 - } 108 + s.server.db.Db.Save(post) 118 109 119 110 return s.profileURL + url.Path, nil 120 111 } ··· 127 118 128 119 id := postIdFromUrlPath(url.Path) 129 120 130 - if err := s.server.db.Docs.DeleteById(string(db.PostCollection), id); err != nil { 131 - return fmt.Errorf("%w: %w", micropub.ErrBadRequest, err) 121 + res := s.server.db.Db.Delete(&models.Post{}, "id = ?", id) 122 + if res.Error != nil { 123 + panic(res.Error) 124 + } else if res.RowsAffected == 0 { 125 + return fmt.Errorf("%w: %w", micropub.ErrNotFound, err) 132 126 } 133 127 134 128 return nil 135 129 } 136 130 137 - func (s *micropubImplementation) Undelete(url string) error { 138 - return micropub.ErrNotImplemented 131 + func (s *micropubImplementation) Undelete(urlStr string) error { 132 + url, err := urlpkg.Parse(urlStr) 133 + if err != nil { 134 + return fmt.Errorf("%w: %w", micropub.ErrBadRequest, err) 135 + } 136 + 137 + id := postIdFromUrlPath(url.Path) 138 + res := s.server.db.Db.Unscoped().Model(&models.Post{}).Where("id = ?", id).Update("deleted_at", nil) 139 + if res.Error != nil { 140 + return res.Error 141 + } else if res.RowsAffected != 1 { 142 + return micropub.ErrNotFound 143 + } 144 + 145 + return nil 139 146 } 140 147 141 148 // updateProperties applies the updates (additions, deletions, replacements) 142 149 // in the given [micropub.Request] to a set of existing microformats properties. 143 - func updateProperties(properties map[string][]any, req *micropub.Request) (map[string][]any, error) { 150 + func updateProperties(props json.RawMessage, req *micropub.Request) ([]byte, error) { 151 + properties := make(map[string][]any) 152 + if err := json.Unmarshal(props, &properties); err != nil { 153 + panic(err) 154 + } 155 + 144 156 if req.Updates.Replace != nil { 145 157 for key, value := range req.Updates.Replace { 146 158 properties[key] = value ··· 208 220 } 209 221 } 210 222 211 - return properties, nil 223 + propJson, err := json.Marshal(&properties) 224 + if err != nil { 225 + panic(err) 226 + } 227 + 228 + return propJson, nil 212 229 }
+19
models/post.go
··· 1 + package models 2 + 3 + import ( 4 + "time" 5 + 6 + "gorm.io/datatypes" 7 + "gorm.io/gorm" 8 + ) 9 + 10 + type Post struct { 11 + ID ULID `gorm:"primaryKey;unique"` 12 + 13 + Type string 14 + Properties datatypes.JSON 15 + 16 + CreatedAt time.Time 17 + UpdatedAt time.Time 18 + DeletedAt gorm.DeletedAt `gorm:"index"` 19 + }
+80
models/ulid.go
··· 1 + package models 2 + 3 + import ( 4 + "database/sql/driver" 5 + 6 + "codeberg.org/gruf/go-ulid" 7 + "gorm.io/gorm" 8 + "gorm.io/gorm/schema" 9 + ) 10 + 11 + type ULID ulid.ULID 12 + 13 + func NewULID() ULID { 14 + return ULID(ulid.MustNew()) 15 + } 16 + 17 + func (ULID) GormDataType() string { 18 + return "string" 19 + } 20 + 21 + func (ULID) GormDBDataType(db *gorm.DB, field *schema.Field) string { 22 + switch db.Dialector.Name() { 23 + case "mysql": 24 + return "LONGTEXT" 25 + case "postgres": 26 + return "UUID" 27 + case "sqlserver": 28 + return "NVARCHAR" 29 + case "sqlite": 30 + return "TEXT" 31 + default: 32 + return "" 33 + } 34 + } 35 + 36 + func (u *ULID) Scan(value interface{}) error { 37 + var result ulid.ULID 38 + if err := result.Scan(value); err != nil { 39 + return err 40 + } 41 + *u = ULID(result) 42 + return nil 43 + } 44 + 45 + func (u ULID) Value() (driver.Value, error) { 46 + return ulid.ULID(u).String(), nil 47 + } 48 + 49 + func (u ULID) String() string { 50 + return ulid.ULID(u).String() 51 + } 52 + 53 + func (u ULID) Equals(other ULID) bool { 54 + return u.String() == other.String() 55 + } 56 + 57 + func (u ULID) Length() int { 58 + return len(u.String()) 59 + } 60 + 61 + func (u ULID) IsNil() bool { 62 + zero, err := ulid.ParseString("0000000000000000") 63 + if err != nil { 64 + panic(err) 65 + } 66 + 67 + return ulid.ULID(u) == zero 68 + } 69 + 70 + func (u ULID) IsEmpty() bool { 71 + return u.IsNil() || u.Length() == 0 72 + } 73 + 74 + func (u *ULID) IsNilPtr() bool { 75 + return u == nil 76 + } 77 + 78 + func (u *ULID) IsEmptyPtr() bool { 79 + return u.IsNilPtr() || u.IsEmpty() 80 + }
+13 -3
pages/home.templ
··· 1 1 package pages 2 2 3 - import "github.com/puregarlic/space/types" 3 + import "github.com/puregarlic/space/models" 4 4 import "fmt" 5 + import "encoding/json" 5 6 6 - templ Home(profileUrl string, posts []*types.Post) { 7 + func getPostPropertyValue(post *models.Post, name string) any { 8 + props := make(map[string]any) 9 + if err := json.Unmarshal(post.Properties, &props); err != nil { 10 + panic(err) 11 + } 12 + 13 + return props[name] 14 + } 15 + 16 + templ Home(profileUrl string, posts []*models.Post) { 7 17 <!DOCTYPE html> 8 18 <html> 9 19 <head> ··· 24 34 <p>You can create posts using a Micropub client.</p> 25 35 <ul> 26 36 for _, post := range posts { 27 - <li><a href={ templ.URL("/posts/" + post.ID) }>{ post.ID }</a> - { fmt.Sprint(post.Properties["content"]) }</li> 37 + <li><a href={ templ.URL("/posts/" + post.ID.String()) }>{ post.ID.String() }</a> - { fmt.Sprint(getPostPropertyValue(post, "content")) }</li> 28 38 } 29 39 </ul> 30 40 </body>
+18 -8
pages/home_templ.go
··· 8 8 import "github.com/a-h/templ" 9 9 import templruntime "github.com/a-h/templ/runtime" 10 10 11 - import "github.com/puregarlic/space/types" 11 + import "github.com/puregarlic/space/models" 12 12 import "fmt" 13 + import "encoding/json" 13 14 14 - func Home(profileUrl string, posts []*types.Post) templ.Component { 15 + func getPostPropertyValue(post *models.Post, name string) any { 16 + props := make(map[string]any) 17 + if err := json.Unmarshal(post.Properties, &props); err != nil { 18 + panic(err) 19 + } 20 + 21 + return props[name] 22 + } 23 + 24 + func Home(profileUrl string, posts []*models.Post) templ.Component { 15 25 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 16 26 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 17 27 templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) ··· 36 46 var templ_7745c5c3_Var2 string 37 47 templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(profileUrl) 38 48 if templ_7745c5c3_Err != nil { 39 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/home.templ`, Line: 20, Col: 77} 49 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/home.templ`, Line: 30, Col: 77} 40 50 } 41 51 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 42 52 if templ_7745c5c3_Err != nil { ··· 51 61 if templ_7745c5c3_Err != nil { 52 62 return templ_7745c5c3_Err 53 63 } 54 - var templ_7745c5c3_Var3 templ.SafeURL = templ.URL("/posts/" + post.ID) 64 + var templ_7745c5c3_Var3 templ.SafeURL = templ.URL("/posts/" + post.ID.String()) 55 65 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3))) 56 66 if templ_7745c5c3_Err != nil { 57 67 return templ_7745c5c3_Err ··· 61 71 return templ_7745c5c3_Err 62 72 } 63 73 var templ_7745c5c3_Var4 string 64 - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(post.ID) 74 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(post.ID.String()) 65 75 if templ_7745c5c3_Err != nil { 66 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/home.templ`, Line: 27, Col: 64} 76 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/home.templ`, Line: 37, Col: 82} 67 77 } 68 78 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 69 79 if templ_7745c5c3_Err != nil { ··· 74 84 return templ_7745c5c3_Err 75 85 } 76 86 var templ_7745c5c3_Var5 string 77 - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(post.Properties["content"])) 87 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(getPostPropertyValue(post, "content"))) 78 88 if templ_7745c5c3_Err != nil { 79 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/home.templ`, Line: 27, Col: 113} 89 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/home.templ`, Line: 37, Col: 142} 80 90 } 81 91 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 82 92 if templ_7745c5c3_Err != nil {
+11 -6
pages/post.templ
··· 1 1 package pages 2 2 3 - import "github.com/puregarlic/space/types" 3 + import "github.com/puregarlic/space/models" 4 4 import "fmt" 5 5 import "encoding/json" 6 6 import "reflect" 7 7 8 - func printProperty(post *types.Post, name string) string { 9 - if val, ok := post.Properties[name]; ok { 8 + func printProperty(post *models.Post, name string) string { 9 + props := make(map[string]any) 10 + if err := json.Unmarshal(post.Properties, &props); err != nil { 11 + panic(err) 12 + } 13 + 14 + if val, ok := props[name]; ok { 10 15 tp := reflect.TypeOf(val) 11 16 switch tp.Kind() { 12 17 default: 13 18 return fmt.Sprint(val) 14 19 case reflect.Slice: 15 20 str := "" 16 - for _, v := range val { 21 + for _, v := range val.([]any) { 17 22 str = str + fmt.Sprint(v) 18 23 } 19 24 ··· 25 30 return "<no name provided>" 26 31 } 27 32 28 - func printPost(post *types.Post) string { 33 + func printPost(post *models.Post) string { 29 34 out, err := json.Marshal(post) 30 35 31 36 if (err != nil) { ··· 35 40 return fmt.Sprint(string(out)) 36 41 } 37 42 38 - templ Post(post *types.Post) { 43 + templ Post(post *models.Post) { 39 44 <!DOCTYPE html> 40 45 <html> 41 46 <head>
+14 -9
pages/post_templ.go
··· 8 8 import "github.com/a-h/templ" 9 9 import templruntime "github.com/a-h/templ/runtime" 10 10 11 - import "github.com/puregarlic/space/types" 11 + import "github.com/puregarlic/space/models" 12 12 import "fmt" 13 13 import "encoding/json" 14 14 import "reflect" 15 15 16 - func printProperty(post *types.Post, name string) string { 17 - if val, ok := post.Properties[name]; ok { 16 + func printProperty(post *models.Post, name string) string { 17 + props := make(map[string]any) 18 + if err := json.Unmarshal(post.Properties, &props); err != nil { 19 + panic(err) 20 + } 21 + 22 + if val, ok := props[name]; ok { 18 23 tp := reflect.TypeOf(val) 19 24 switch tp.Kind() { 20 25 default: 21 26 return fmt.Sprint(val) 22 27 case reflect.Slice: 23 28 str := "" 24 - for _, v := range val { 29 + for _, v := range val.([]any) { 25 30 str = str + fmt.Sprint(v) 26 31 } 27 32 ··· 33 38 return "<no name provided>" 34 39 } 35 40 36 - func printPost(post *types.Post) string { 41 + func printPost(post *models.Post) string { 37 42 out, err := json.Marshal(post) 38 43 39 44 if err != nil { ··· 43 48 return fmt.Sprint(string(out)) 44 49 } 45 50 46 - func Post(post *types.Post) templ.Component { 51 + func Post(post *models.Post) templ.Component { 47 52 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 48 53 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 49 54 templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) ··· 90 95 var templ_7745c5c3_Var4 string 91 96 templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(printProperty(post, "name")) 92 97 if templ_7745c5c3_Err != nil { 93 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/post.templ`, Line: 46, Col: 56} 98 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/post.templ`, Line: 51, Col: 56} 94 99 } 95 100 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 96 101 if templ_7745c5c3_Err != nil { ··· 103 108 var templ_7745c5c3_Var5 string 104 109 templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(printProperty(post, "content")) 105 110 if templ_7745c5c3_Err != nil { 106 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/post.templ`, Line: 47, Col: 61} 111 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/post.templ`, Line: 52, Col: 61} 107 112 } 108 113 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 109 114 if templ_7745c5c3_Err != nil { ··· 116 121 var templ_7745c5c3_Var6 string 117 122 templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(printPost(post)) 118 123 if templ_7745c5c3_Err != nil { 119 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/post.templ`, Line: 51, Col: 32} 124 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/post.templ`, Line: 56, Col: 32} 120 125 } 121 126 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 122 127 if templ_7745c5c3_Err != nil {
-8
types/post.go
··· 1 - package types 2 - 3 - type Post struct { 4 - ID string `clover:""` 5 - CreatedAt int64 `clover:"createdAt"` 6 - Type string `clover:"type"` 7 - Properties map[string][]any `clover:"properties"` 8 - }