- commit
- 90d8d20
- parent
- 90d8d20
- author
- Eric Bower
- date
- 2022-07-27 16:00:54 +0000 UTC
init
+14,
-0
1@@ -0,0 +1,14 @@
2+*.log
3+*.swp
4+.env
5+.envrc
6+build/*
7+!build/.gitkeep
8+ssh_data/*
9+!ssh_data/.gitkeep
10+caddy_data/*
11+!caddy_data/.gitkeep
12+caddy_config/*
13+!caddy_config/.gitkeep
14+.env.prod
15+*.bak
+40,
-0
1@@ -0,0 +1,40 @@
2+CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
3+
4+CREATE TABLE IF NOT EXISTS app_users (
5+ id uuid NOT NULL DEFAULT uuid_generate_v4(),
6+ name character varying(50),
7+ created_at timestamp without time zone NOT NULL DEFAULT NOW(),
8+ CONSTRAINT unique_name UNIQUE (name),
9+ CONSTRAINT app_user_pkey PRIMARY KEY (id)
10+);
11+
12+CREATE TABLE IF NOT EXISTS public_keys (
13+ id uuid NOT NULL DEFAULT uuid_generate_v4(),
14+ user_id uuid NOT NULL,
15+ public_key varchar(2048) NOT NULL,
16+ created_at timestamp without time zone NOT NULL DEFAULT NOW(),
17+ CONSTRAINT user_public_keys_pkey PRIMARY KEY (id),
18+ CONSTRAINT unique_key_for_user UNIQUE (user_id, public_key),
19+ CONSTRAINT fk_user_public_keys_owner
20+ FOREIGN KEY(user_id)
21+ REFERENCES app_users(id)
22+ ON DELETE CASCADE
23+ ON UPDATE CASCADE
24+);
25+
26+CREATE TABLE IF NOT EXISTS posts (
27+ id uuid NOT NULL DEFAULT uuid_generate_v4(),
28+ user_id uuid NOT NULL,
29+ title character varying(255) NOT NULL,
30+ text text NOT NULL DEFAULT '',
31+ publish_at timestamp without time zone NOT NULL DEFAULT NOW(),
32+ created_at timestamp without time zone NOT NULL DEFAULT NOW(),
33+ updated_at timestamp without time zone NOT NULL DEFAULT NOW(),
34+ CONSTRAINT posts_pkey PRIMARY KEY (id),
35+ CONSTRAINT unique_title_for_user UNIQUE (user_id, title),
36+ CONSTRAINT fk_posts_app_users
37+ FOREIGN KEY(user_id)
38+ REFERENCES app_users(id)
39+ ON DELETE CASCADE
40+ ON UPDATE CASCADE
41+);
1@@ -0,0 +1,8 @@
2+ALTER TABLE app_users ADD COLUMN bio character varying(150) NOT NULL DEFAULT '';
3+ALTER TABLE posts ADD COLUMN description character varying(150) NOT NULL DEFAULT '';
4+ALTER TABLE posts ADD COLUMN filename character varying(255);
5+
6+UPDATE posts SET filename = title;
7+
8+ALTER TABLE posts ADD CONSTRAINT unique_filename_for_user UNIQUE (user_id, filename);
9+ALTER TABLE posts DROP CONSTRAINT unique_title_for_user;
1@@ -0,0 +1,2 @@
2+CREATE INDEX posts_filename ON posts USING btree(filename);
3+ALTER TABLE app_users DROP COLUMN bio;
1@@ -0,0 +1 @@
2+UPDATE app_users SET name = LOWER(name) WHERE name != LOWER(name);
1@@ -0,0 +1,5 @@
2+ALTER TABLE posts ALTER COLUMN updated_at TYPE timestamp WITH TIME ZONE USING updated_at AT TIME ZONE 'UTC';
3+ALTER TABLE posts ALTER COLUMN publish_at TYPE timestamp WITH TIME ZONE USING publish_at AT TIME ZONE 'UTC';
4+ALTER TABLE posts ALTER COLUMN created_at TYPE timestamp WITH TIME ZONE USING created_at AT TIME ZONE 'UTC';
5+ALTER TABLE app_users ALTER COLUMN created_at TYPE timestamp WITH TIME ZONE USING created_at AT TIME ZONE 'UTC';
6+ALTER TABLE public_keys ALTER COLUMN created_at TYPE timestamp WITH TIME ZONE USING created_at AT TIME ZONE 'UTC';
+12,
-0
1@@ -0,0 +1,12 @@
2+CREATE TABLE IF NOT EXISTS post_analytics (
3+ id uuid NOT NULL DEFAULT uuid_generate_v4(),
4+ post_id uuid NOT NULL,
5+ views int DEFAULT 0,
6+ updated_at timestamp without time zone NOT NULL DEFAULT NOW(),
7+ CONSTRAINT analytics_pkey PRIMARY KEY (id),
8+ CONSTRAINT fk_analytics_posts
9+ FOREIGN KEY(post_id)
10+ REFERENCES posts(id)
11+ ON DELETE CASCADE
12+ ON UPDATE CASCADE
13+);
1@@ -0,0 +1,2 @@
2+ALTER TABLE posts ADD COLUMN hidden boolean NOT NULL DEFAULT FALSE;
3+UPDATE posts SET hidden = TRUE WHERE filename LIKE E'\\_%';
1@@ -0,0 +1,8 @@
2+CREATE TYPE space AS ENUM ('prose', 'lists', 'pastes', 'imgs');
3+
4+ALTER TABLE posts ADD COLUMN cur_space space;
5+ALTER TABLE posts ADD COLUMN views int DEFAULT 0;
6+ALTER TABLE posts DROP CONSTRAINT unique_filename_for_user;
7+ALTER TABLE posts ADD CONSTRAINT unique_filename_for_user UNIQUE (user_id, cur_space, filename);
8+
9+DROP TABLE post_analytics;
+1,
-0
1@@ -0,0 +1 @@
2+CREATE DATABASE "pico" OWNER "postgres";
+3,
-0
1@@ -0,0 +1,3 @@
2+DROP TABLE posts CASCADE;
3+DROP TABLE app_users CASCADE;
4+DROP TABLE public_keys CASCADE;
+9,
-0
1@@ -0,0 +1,9 @@
2+version: "3.4"
3+services:
4+ db:
5+ image: postgres
6+ restart: always
7+ ports:
8+ - "5432:5432"
9+ env_file:
10+ - .env
A
go.mod
+17,
-0
1@@ -0,0 +1,17 @@
2+module git.sr.ht/~erock/pico
3+
4+go 1.18
5+
6+replace git.sr.ht/~erock/wish => /home/erock/pico/wish
7+
8+require (
9+ git.sr.ht/~erock/wish v0.0.0-20220723165654-ad295e939d88
10+ go.uber.org/zap v1.21.0
11+)
12+
13+require (
14+ github.com/lib/pq v1.10.6 // indirect
15+ go.uber.org/atomic v1.7.0 // indirect
16+ go.uber.org/multierr v1.6.0 // indirect
17+ golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d // indirect
18+)
A
go.sum
+61,
-0
1@@ -0,0 +1,61 @@
2+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
3+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
4+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
8+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
9+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
10+github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
11+github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
12+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
13+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
14+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
17+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
18+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
19+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
20+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
21+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
22+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
23+go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
24+go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
25+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
26+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
27+go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
28+go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
29+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
30+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
31+golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0=
32+golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
33+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
34+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
35+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
36+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
37+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
38+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
39+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
40+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
41+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
42+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
43+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
44+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
45+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
46+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
47+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
48+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
49+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
50+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
51+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
52+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
53+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
54+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
55+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
56+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
57+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
58+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
59+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
60+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
61+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
62+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
A
main.go
+268,
-0
1@@ -0,0 +1,268 @@
2+package main
3+
4+import (
5+ "context"
6+ "database/sql"
7+ "fmt"
8+ "log"
9+ "os"
10+
11+ "git.sr.ht/~erock/wish/cms/config"
12+ "git.sr.ht/~erock/wish/cms/db"
13+ "git.sr.ht/~erock/wish/cms/db/postgres"
14+ "go.uber.org/zap"
15+)
16+
17+func createLogger() *zap.SugaredLogger {
18+ logger, err := zap.NewProduction()
19+ if err != nil {
20+ log.Fatal(err)
21+ }
22+
23+ return logger.Sugar()
24+}
25+
26+func InsertUser(tx *sql.Tx, user *db.User) error {
27+ _, err := tx.Exec(
28+ "INSERT INTO app_users (id, name, created_at) VALUES($1, $2, $3)",
29+ user.ID,
30+ user.Name,
31+ user.CreatedAt,
32+ )
33+ return err
34+}
35+
36+func InsertPublicKey(tx *sql.Tx, pk *db.PublicKey) error {
37+ _, err := tx.Exec(
38+ "INSERT INTO public_keys (id, user_id, public_key, created_at) VALUES ($1, $2, $3, $4)",
39+ pk.ID,
40+ pk.UserID,
41+ pk.Key,
42+ pk.CreatedAt,
43+ )
44+ return err
45+}
46+
47+func InsertPost(tx *sql.Tx, post *db.Post) error {
48+ _, err := tx.Exec(
49+ `INSERT INTO posts
50+ (id, user_id, title, text, created_at, publish_at, updated_at, description, filename, hidden, cur_space)
51+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
52+ post.ID,
53+ post.UserID,
54+ post.Title,
55+ post.Text,
56+ post.CreatedAt,
57+ post.PublishAt,
58+ post.UpdatedAt,
59+ post.Description,
60+ post.Filename,
61+ post.Hidden,
62+ post.Space,
63+ )
64+ return err
65+}
66+
67+type ConflictData struct {
68+ User *db.User
69+ Pks []*db.PublicKey
70+ ReplaceWithID string
71+}
72+
73+func main() {
74+ logger := createLogger()
75+
76+ listsCfg := config.NewConfigCms()
77+ listsCfg.Logger = logger
78+ listsCfg.DbURL = os.Getenv("LISTS_DB_URL")
79+ listsDb := postgres.NewDB(listsCfg)
80+
81+ proseCfg := config.NewConfigCms()
82+ proseCfg.DbURL = os.Getenv("PROSE_DB_URL")
83+ proseCfg.Logger = logger
84+ proseDb := postgres.NewDB(proseCfg)
85+
86+ picoCfg := config.NewConfigCms()
87+ picoCfg.Logger = logger
88+ picoCfg.DbURL = os.Getenv("PICO_DB_URL")
89+ picoDb := postgres.NewDB(picoCfg)
90+
91+ ctx := context.Background()
92+ tx, err := picoDb.Db.BeginTx(ctx, nil)
93+ if err != nil {
94+ panic(err)
95+ }
96+ rollback := func() {
97+ // Defer a rollback in case anything fails.
98+ defer tx.Rollback()
99+ }
100+ defer rollback()
101+
102+ logger.Info("delete users where name is null")
103+ _, err = tx.Exec("DELETE FROM app_users WHERE name IS NULL")
104+ if err != nil {
105+ panic(err)
106+ }
107+
108+ proseUsers, err := proseDb.FindUsers()
109+ if err != nil {
110+ panic(err)
111+ }
112+
113+ listUsers, err := listsDb.FindUsers()
114+ if err != nil {
115+ panic(err)
116+ }
117+
118+ userMap := map[string]*db.User{}
119+ for _, proseUser := range proseUsers {
120+ userMap[proseUser.Name] = proseUser
121+
122+ err = InsertUser(tx, proseUser)
123+ if err != nil {
124+ panic(err)
125+ }
126+ }
127+
128+ noconflicts := []*ConflictData{}
129+ conflicts := []*ConflictData{}
130+ updateIDs := []*ConflictData{}
131+ logger.Info("Finding conflicts")
132+ for _, listUser := range listUsers {
133+ listKeys, err := listsDb.FindKeysForUser(listUser)
134+ if err != nil {
135+ panic(err)
136+ }
137+
138+ data := &ConflictData{
139+ User: listUser,
140+ Pks: listKeys,
141+ }
142+
143+ if userMap[listUser.Name] == nil {
144+ noconflicts = append(noconflicts, data)
145+ continue
146+ } else {
147+ proseUser := userMap[listUser.Name]
148+ proseKeys, err := proseDb.FindKeysForUser(proseUser)
149+ if err != nil {
150+ panic(err)
151+ }
152+
153+ if len(listKeys) != len(proseKeys) {
154+ conflicts = append(conflicts, data)
155+ continue
156+ }
157+
158+ pkMap := map[string]bool{}
159+ for _, prosePK := range proseKeys {
160+ pkMap[prosePK.Key] = true
161+
162+ err = InsertPublicKey(tx, prosePK)
163+ if err != nil {
164+ panic(err)
165+ }
166+ }
167+
168+ conflicted := false
169+ for _, listPK := range listKeys {
170+ if !pkMap[listPK.Key] {
171+ conflicted = true
172+ conflicts = append(conflicts, data)
173+ break
174+ }
175+ }
176+
177+ if !conflicted {
178+ data.ReplaceWithID = proseUser.ID
179+ updateIDs = append(updateIDs, data)
180+ }
181+ }
182+ }
183+
184+ logger.Infof("Adding records with no conflicts (%d)", len(noconflicts))
185+ for _, data := range noconflicts {
186+ err = InsertUser(tx, data.User)
187+ if err != nil {
188+ panic(err)
189+ }
190+
191+ for _, pk := range data.Pks {
192+ err = InsertPublicKey(tx, pk)
193+ if err != nil {
194+ panic(err)
195+ }
196+ }
197+ }
198+
199+ logger.Infof("Adding records with conflicts (%d)", len(conflicts))
200+ for _, data := range conflicts {
201+ data.User.Name = fmt.Sprintf("%stmp", data.User.Name)
202+ err = InsertUser(tx, data.User)
203+ if err != nil {
204+ panic(err)
205+ }
206+
207+ for _, pk := range data.Pks {
208+ err = InsertPublicKey(tx, pk)
209+ if err != nil {
210+ panic(err)
211+ }
212+ }
213+ }
214+
215+ prosePosts, err := proseDb.FindPosts()
216+ if err != nil {
217+ panic(err)
218+ }
219+
220+ logger.Info("Adding posts from prose.sh")
221+ for _, post := range prosePosts {
222+ post.Space = "prose"
223+ err = InsertPost(tx, post)
224+ if err != nil {
225+ panic(err)
226+ }
227+ }
228+
229+ listPosts, err := listsDb.FindPosts()
230+ if err != nil {
231+ panic(err)
232+ }
233+
234+ logger.Info("Adding posts from lists.sh")
235+ for _, post := range listPosts {
236+ updated := false
237+ for _, alreadyAdded := range updateIDs {
238+ if post.UserID == alreadyAdded.User.ID {
239+ // we need to change the ID for these posts to the prose user id
240+ // because we were able to determine it was the same user
241+ post.UserID = alreadyAdded.ReplaceWithID
242+ post.Space = "lists"
243+ err = InsertPost(tx, post)
244+ if err != nil {
245+ fmt.Println(post.Filename)
246+ panic(err)
247+ }
248+ updated = true
249+ break
250+ }
251+ }
252+
253+ if updated {
254+ continue
255+ }
256+
257+ post.Space = "lists"
258+ err = InsertPost(tx, post)
259+ if err != nil {
260+ panic(err)
261+ }
262+ }
263+
264+ logger.Info("Committing transactions to PICO db")
265+ // Commit the transaction.
266+ /* if err = tx.Commit(); err != nil {
267+ panic(err)
268+ } */
269+}
A
makefile
+79,
-0
1@@ -0,0 +1,79 @@
2+PGDATABASE?="pico"
3+PGHOST?="db"
4+PGUSER?="postgres"
5+PORT?="5432"
6+DB_CONTAINER?=pico-services_db_1
7+
8+test:
9+ docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:latest golangci-lint run -E goimports -E godot
10+.PHONY: test
11+
12+build:
13+ go build -o build/web ./cmd/web
14+ go build -o build/ssh ./cmd/ssh
15+.PHONY: build
16+
17+format:
18+ go fmt ./...
19+.PHONY: format
20+
21+create:
22+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) < ./db/setup.sql
23+.PHONY: create
24+
25+teardown:
26+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/teardown.sql
27+.PHONY: teardown
28+
29+migrate:
30+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220310_init.sql
31+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220422_add_desc_to_user_and_post.sql
32+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220426_add_index_for_filename.sql
33+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220427_username_to_lower.sql
34+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220523_timestamp_with_tz.sql
35+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220721_analytics.sql
36+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220722_post_hidden.sql
37+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220727_post_change_post_contraints.sql
38+.PHONY: migrate
39+
40+latest:
41+ docker exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./db/migrations/20220727_post_change_post_contraints.sql
42+.PHONY: latest
43+
44+psql:
45+ docker exec -it $(DB_CONTAINER) psql -U $(PGUSER)
46+.PHONY: psql
47+
48+dump:
49+ docker exec -it $(DB_CONTAINER) pg_dump -U $(PGUSER) $(PGDATABASE) > ./backup.sql
50+.PHONY: dump
51+
52+restore:
53+ docker cp ./backup.sql $(DB_CONTAINER):/backup.sql
54+ docker exec -it $(DB_CONTAINER) /bin/bash
55+ # psql postgres -U postgres < /backup.sql
56+.PHONY: restore
57+
58+bp-caddy:
59+ docker build -t neurosnap/prose-caddy -f Dockerfile.caddy .
60+ docker push neurosnap/prose-caddy
61+.PHONY: bp-caddy
62+
63+bp-ssh:
64+ docker build -t neurosnap/prose-ssh --target ssh .
65+ docker push neurosnap/prose-ssh
66+.PHONY: bp-ssh
67+
68+bp-web:
69+ docker build -t neurosnap/prose-web --target web .
70+ docker push neurosnap/prose-web
71+.PHONY: bp-web
72+
73+bp: bp-ssh bp-web bp-caddy
74+.PHONY: bp
75+
76+deploy:
77+ docker system prune -f
78+ docker-compose -f production.yml pull --ignore-pull-failures
79+ docker-compose -f production.yml up --no-deps -d
80+.PHONY: deploy