tkadkghdlf commited on
Commit
dd5c83c
·
verified ·
1 Parent(s): e0ce9a3

Sync from GitHub via hub-sync

Browse files
api/auth-service/alembic/versions/0006_create_refresh_tokens.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from alembic import op
2
+ import sqlalchemy as sa
3
+
4
+ revision = "0006_create_refresh_tokens"
5
+ down_revision = "0005_create_email_verification_codes"
6
+ branch_labels = None
7
+ depends_on = None
8
+
9
+
10
+ def upgrade() -> None:
11
+ op.create_table(
12
+ "refresh_tokens",
13
+ sa.Column("id", sa.Integer(), primary_key=True),
14
+ sa.Column("user_id", sa.Integer(), nullable=False),
15
+ sa.Column("token_hash", sa.String(length=64), nullable=False),
16
+ sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False),
17
+ sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True),
18
+ sa.Column(
19
+ "created_at",
20
+ sa.DateTime(timezone=True),
21
+ nullable=False,
22
+ server_default=sa.text("now()"),
23
+ ),
24
+ sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
25
+ )
26
+ op.create_index(
27
+ "ix_refresh_tokens_user_id",
28
+ "refresh_tokens",
29
+ ["user_id"],
30
+ unique=False,
31
+ )
32
+ op.create_index(
33
+ "ix_refresh_tokens_token_hash",
34
+ "refresh_tokens",
35
+ ["token_hash"],
36
+ unique=True,
37
+ )
38
+ op.create_index(
39
+ "ix_refresh_tokens_expires_at",
40
+ "refresh_tokens",
41
+ ["expires_at"],
42
+ unique=False,
43
+ )
44
+
45
+
46
+ def downgrade() -> None:
47
+ op.drop_index(
48
+ "ix_refresh_tokens_expires_at",
49
+ table_name="refresh_tokens",
50
+ )
51
+ op.drop_index(
52
+ "ix_refresh_tokens_token_hash",
53
+ table_name="refresh_tokens",
54
+ )
55
+ op.drop_index(
56
+ "ix_refresh_tokens_user_id",
57
+ table_name="refresh_tokens",
58
+ )
59
+ op.drop_table("refresh_tokens")
api/auth-service/alembic/versions/0007_create_community_tables.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from alembic import op
2
+ import sqlalchemy as sa
3
+ from sqlalchemy.dialects import postgresql
4
+
5
+ revision = "0007_create_community_tables"
6
+ down_revision = "0006_create_refresh_tokens"
7
+ branch_labels = None
8
+ depends_on = None
9
+
10
+
11
+ def _constraint_exists(bind, table_name: str, constraint_name: str) -> bool:
12
+ row = bind.execute(
13
+ sa.text(
14
+ """
15
+ SELECT 1
16
+ FROM pg_constraint c
17
+ JOIN pg_class t ON t.oid = c.conrelid
18
+ JOIN pg_namespace n ON n.oid = t.relnamespace
19
+ WHERE n.nspname = current_schema()
20
+ AND t.relname = :table_name
21
+ AND c.conname = :constraint_name
22
+ LIMIT 1
23
+ """
24
+ ),
25
+ {"table_name": table_name, "constraint_name": constraint_name},
26
+ ).first()
27
+ return row is not None
28
+
29
+
30
+ def upgrade() -> None:
31
+ bind = op.get_bind()
32
+ inspector = sa.inspect(bind)
33
+
34
+ if not inspector.has_table("community_posts"):
35
+ op.create_table(
36
+ "community_posts",
37
+ sa.Column("id", sa.BigInteger(), primary_key=True),
38
+ sa.Column("user_id", sa.Integer(), nullable=False),
39
+ sa.Column("run_session_id", sa.BigInteger(), nullable=True),
40
+ sa.Column("route_id", sa.BigInteger(), nullable=True),
41
+ sa.Column("title", sa.String(length=255), nullable=False),
42
+ sa.Column("content", sa.Text(), nullable=False),
43
+ sa.Column(
44
+ "visibility",
45
+ sa.String(length=20),
46
+ nullable=False,
47
+ server_default=sa.text("'public'"),
48
+ ),
49
+ sa.Column("difficulty", sa.String(length=50), nullable=True),
50
+ sa.Column(
51
+ "tags",
52
+ postgresql.JSONB(astext_type=sa.Text()),
53
+ nullable=False,
54
+ server_default=sa.text("'[]'::jsonb"),
55
+ ),
56
+ sa.Column("like_count", sa.Integer(), nullable=False, server_default=sa.text("0")),
57
+ sa.Column("comment_count", sa.Integer(), nullable=False, server_default=sa.text("0")),
58
+ sa.Column("view_count", sa.Integer(), nullable=False, server_default=sa.text("0")),
59
+ sa.Column(
60
+ "created_at",
61
+ sa.DateTime(timezone=True),
62
+ nullable=False,
63
+ server_default=sa.text("now()"),
64
+ ),
65
+ sa.Column(
66
+ "updated_at",
67
+ sa.DateTime(timezone=True),
68
+ nullable=False,
69
+ server_default=sa.text("now()"),
70
+ ),
71
+ sa.CheckConstraint(
72
+ "(run_session_id IS NOT NULL) OR (route_id IS NOT NULL)",
73
+ name="chk_post_target",
74
+ ),
75
+ sa.CheckConstraint(
76
+ "visibility IN ('public', 'private')",
77
+ name="ck_community_posts_visibility",
78
+ ),
79
+ sa.CheckConstraint(
80
+ "like_count >= 0",
81
+ name="ck_community_posts_like_count_non_negative",
82
+ ),
83
+ sa.CheckConstraint(
84
+ "comment_count >= 0",
85
+ name="ck_community_posts_comment_count_non_negative",
86
+ ),
87
+ sa.CheckConstraint(
88
+ "view_count >= 0",
89
+ name="ck_community_posts_view_count_non_negative",
90
+ ),
91
+ sa.CheckConstraint(
92
+ "jsonb_typeof(tags) = 'array'",
93
+ name="ck_community_posts_tags_is_array",
94
+ ),
95
+ sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
96
+ sa.ForeignKeyConstraint(["run_session_id"], ["run_sessions.id"], ondelete="SET NULL"),
97
+ sa.ForeignKeyConstraint(["route_id"], ["routes.id"], ondelete="SET NULL"),
98
+ )
99
+
100
+ inspector = sa.inspect(bind)
101
+ post_columns = {column["name"] for column in inspector.get_columns("community_posts")}
102
+
103
+ if "difficulty" not in post_columns:
104
+ op.add_column("community_posts", sa.Column("difficulty", sa.String(length=50), nullable=True))
105
+
106
+ if "tags" not in post_columns:
107
+ op.add_column(
108
+ "community_posts",
109
+ sa.Column(
110
+ "tags",
111
+ postgresql.JSONB(astext_type=sa.Text()),
112
+ nullable=False,
113
+ server_default=sa.text("'[]'::jsonb"),
114
+ ),
115
+ )
116
+
117
+ if "view_count" not in post_columns:
118
+ op.add_column(
119
+ "community_posts",
120
+ sa.Column(
121
+ "view_count",
122
+ sa.Integer(),
123
+ nullable=False,
124
+ server_default=sa.text("0"),
125
+ ),
126
+ )
127
+
128
+ if not _constraint_exists(bind, "community_posts", "ck_community_posts_view_count_non_negative"):
129
+ op.create_check_constraint(
130
+ "ck_community_posts_view_count_non_negative",
131
+ "community_posts",
132
+ "view_count >= 0",
133
+ )
134
+
135
+ if not _constraint_exists(bind, "community_posts", "ck_community_posts_tags_is_array"):
136
+ op.create_check_constraint(
137
+ "ck_community_posts_tags_is_array",
138
+ "community_posts",
139
+ "jsonb_typeof(tags) = 'array'",
140
+ )
141
+
142
+ op.execute("CREATE INDEX IF NOT EXISTS idx_community_posts_user ON community_posts (user_id)")
143
+ op.execute("CREATE INDEX IF NOT EXISTS idx_community_posts_route ON community_posts (route_id)")
144
+ op.execute(
145
+ "CREATE INDEX IF NOT EXISTS idx_community_posts_run_session ON community_posts (run_session_id)"
146
+ )
147
+ op.execute(
148
+ "CREATE INDEX IF NOT EXISTS idx_community_posts_created_at "
149
+ "ON community_posts (created_at DESC)"
150
+ )
151
+ op.execute(
152
+ "CREATE INDEX IF NOT EXISTS idx_community_posts_visibility_created "
153
+ "ON community_posts (visibility, created_at DESC)"
154
+ )
155
+
156
+ if not inspector.has_table("community_reactions"):
157
+ op.create_table(
158
+ "community_reactions",
159
+ sa.Column("id", sa.BigInteger(), primary_key=True),
160
+ sa.Column("post_id", sa.BigInteger(), nullable=False),
161
+ sa.Column("user_id", sa.Integer(), nullable=False),
162
+ sa.Column("reaction_type", sa.String(length=20), nullable=False),
163
+ sa.Column("comment_text", sa.Text(), nullable=True),
164
+ sa.Column(
165
+ "created_at",
166
+ sa.DateTime(timezone=True),
167
+ nullable=False,
168
+ server_default=sa.text("now()"),
169
+ ),
170
+ sa.CheckConstraint(
171
+ "reaction_type IN ('like', 'comment')",
172
+ name="ck_community_reactions_type",
173
+ ),
174
+ sa.CheckConstraint(
175
+ "(reaction_type = 'like' AND comment_text IS NULL) OR "
176
+ "(reaction_type = 'comment' AND char_length(trim(comment_text)) > 0)",
177
+ name="ck_community_reactions_comment_text",
178
+ ),
179
+ sa.ForeignKeyConstraint(["post_id"], ["community_posts.id"], ondelete="CASCADE"),
180
+ sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
181
+ )
182
+
183
+ op.execute(
184
+ "CREATE INDEX IF NOT EXISTS idx_community_reactions_post_created "
185
+ "ON community_reactions (post_id, created_at DESC)"
186
+ )
187
+ op.execute("CREATE INDEX IF NOT EXISTS idx_community_reactions_user ON community_reactions (user_id)")
188
+ op.execute(
189
+ "CREATE INDEX IF NOT EXISTS idx_community_reactions_post_type_created "
190
+ "ON community_reactions (post_id, reaction_type, created_at DESC)"
191
+ )
192
+ op.execute(
193
+ "CREATE UNIQUE INDEX IF NOT EXISTS uq_community_reactions_like_once "
194
+ "ON community_reactions (post_id, user_id) WHERE reaction_type = 'like'"
195
+ )
196
+
197
+
198
+ def downgrade() -> None:
199
+ bind = op.get_bind()
200
+ inspector = sa.inspect(bind)
201
+
202
+ op.execute("DROP INDEX IF EXISTS uq_community_reactions_like_once")
203
+ op.execute("DROP INDEX IF EXISTS idx_community_reactions_post_type_created")
204
+
205
+ if inspector.has_table("community_posts"):
206
+ if _constraint_exists(bind, "community_posts", "ck_community_posts_tags_is_array"):
207
+ op.drop_constraint(
208
+ "ck_community_posts_tags_is_array",
209
+ "community_posts",
210
+ type_="check",
211
+ )
212
+ if _constraint_exists(bind, "community_posts", "ck_community_posts_view_count_non_negative"):
213
+ op.drop_constraint(
214
+ "ck_community_posts_view_count_non_negative",
215
+ "community_posts",
216
+ type_="check",
217
+ )
218
+
219
+ op.execute("ALTER TABLE community_posts DROP COLUMN IF EXISTS view_count")
220
+ op.execute("ALTER TABLE community_posts DROP COLUMN IF EXISTS tags")
221
+ op.execute("ALTER TABLE community_posts DROP COLUMN IF EXISTS difficulty")