@meith/db 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +165 -0
- package/migrations/0000_initial_schema.sql +538 -0
- package/migrations/0001_seed_usergroups.sql +111 -0
- package/migrations/0002_group_promotions.sql +25 -0
- package/migrations/0003_counter_maintenance.sql +34 -0
- package/migrations/0004_post_render_cache.sql +7 -0
- package/migrations/0005_reports.sql +51 -0
- package/migrations/0006_warnings.sql +91 -0
- package/migrations/0007_notifications.sql +44 -0
- package/migrations/0008_subscriptions.sql +48 -0
- package/migrations/0009_member_preferences.sql +13 -0
- package/migrations/0010_profile_fields.sql +53 -0
- package/migrations/0011_private_messages.sql +63 -0
- package/migrations/0012_user_relations.sql +18 -0
- package/migrations/0013_reputation.sql +45 -0
- package/migrations/0014_signatures.sql +16 -0
- package/migrations/0015_admin_sessions.sql +24 -0
- package/migrations/0016_attachments.sql +51 -0
- package/migrations/0017_avatars.sql +33 -0
- package/migrations/0018_mass_mail.sql +15 -0
- package/migrations/0019_word_filters.sql +8 -0
- package/migrations/0020_searches.sql +15 -0
- package/migrations/0021_presence_stats.sql +18 -0
- package/migrations/0022_api_tokens_webhooks.sql +58 -0
- package/migrations/0023_install_state.sql +6 -0
- package/migrations/0024_component_versions.sql +13 -0
- package/migrations/0025_import.sql +25 -0
- package/migrations/0026_polls.sql +40 -0
- package/migrations/0027_drafts.sql +13 -0
- package/migrations/0028_board_vocabulary.sql +32 -0
- package/migrations/0029_announcements.sql +16 -0
- package/migrations/0030_antispam.sql +18 -0
- package/migrations/0031_markdown.sql +24 -0
- package/migrations/0032_theme_enablement.sql +1 -0
- package/migrations/0033_group_identity.sql +5 -0
- package/migrations/0034_search_document_version.sql +4 -0
- package/migrations/0035_categories_hold_no_threads.sql +1 -0
- package/migrations/0036_expiring_group_grants.sql +6 -0
- package/migrations/0037_automatic_timezone.sql +3 -0
- package/migrations/0038_primary_group_grants.sql +3 -0
- package/migrations/0039_moderator_log_forum_scope.sql +1 -0
- package/migrations/0040_moderator_restore_grants.sql +1 -0
- package/migrations/0041_drop_placebo_moderator_rights.sql +3 -0
- package/migrations/0042_drop_placebo_delete_others.sql +2 -0
- package/migrations/0043_federated_identity.sql +28 -0
- package/migrations/0044_second_factor.sql +34 -0
- package/migrations/0045_drop_dead_task_due_index.sql +1 -0
- package/migrations/0046_member_locale.sql +1 -0
- package/migrations/0047_navigation_items.sql +34 -0
- package/migrations/0048_web_push.sql +16 -0
- package/migrations/0049_plugin_health.sql +7 -0
- package/migrations/0050_drop_forum_password_grants.sql +1 -0
- package/migrations/0051_glossy_barracuda.sql +1 -0
- package/migrations/0052_many_professor_monster.sql +2 -0
- package/migrations/0053_strange_maximus.sql +14 -0
- package/migrations/0054_legacy_import_sources.sql +25 -0
- package/migrations/0055_poll_parity.sql +14 -0
- package/migrations/0056_marketplace_catalog.sql +11 -0
- package/migrations/meta/0000_snapshot.json +4412 -0
- package/migrations/meta/0006_snapshot.json +5411 -0
- package/migrations/meta/0007_snapshot.json +5634 -0
- package/migrations/meta/0008_snapshot.json +5779 -0
- package/migrations/meta/0009_snapshot.json +5816 -0
- package/migrations/meta/0010_snapshot.json +6117 -0
- package/migrations/meta/0011_snapshot.json +6406 -0
- package/migrations/meta/0012_snapshot.json +6517 -0
- package/migrations/meta/0013_snapshot.json +6722 -0
- package/migrations/meta/0014_snapshot.json +6777 -0
- package/migrations/meta/0015_snapshot.json +6914 -0
- package/migrations/meta/0016_snapshot.json +7192 -0
- package/migrations/meta/0017_snapshot.json +7248 -0
- package/migrations/meta/0018_snapshot.json +7355 -0
- package/migrations/meta/0019_snapshot.json +7419 -0
- package/migrations/meta/0020_snapshot.json +7562 -0
- package/migrations/meta/0021_snapshot.json +7653 -0
- package/migrations/meta/0031_snapshot.json +8162 -0
- package/migrations/meta/0032_snapshot.json +8169 -0
- package/migrations/meta/0033_snapshot.json +8193 -0
- package/migrations/meta/0034_snapshot.json +8221 -0
- package/migrations/meta/0036_snapshot.json +8262 -0
- package/migrations/meta/0037_snapshot.json +8262 -0
- package/migrations/meta/0038_snapshot.json +8293 -0
- package/migrations/meta/0039_snapshot.json +8308 -0
- package/migrations/meta/0041_snapshot.json +8287 -0
- package/migrations/meta/0042_snapshot.json +8274 -0
- package/migrations/meta/0043_snapshot.json +8521 -0
- package/migrations/meta/0044_snapshot.json +8814 -0
- package/migrations/meta/0045_snapshot.json +8797 -0
- package/migrations/meta/0046_snapshot.json +8804 -0
- package/migrations/meta/0047_snapshot.json +9018 -0
- package/migrations/meta/0048_snapshot.json +9145 -0
- package/migrations/meta/0049_snapshot.json +9190 -0
- package/migrations/meta/0050_snapshot.json +9126 -0
- package/migrations/meta/0051_snapshot.json +9132 -0
- package/migrations/meta/0052_snapshot.json +9148 -0
- package/migrations/meta/0053_snapshot.json +9268 -0
- package/migrations/meta/0054_snapshot.json +9378 -0
- package/migrations/meta/0056_snapshot.json +9447 -0
- package/migrations/meta/_journal.json +405 -0
- package/package.json +64 -0
- package/src/account-repos.ts +580 -0
- package/src/actor-builder.ts +130 -0
- package/src/admin-repo.ts +85 -0
- package/src/admin-session-repo.ts +205 -0
- package/src/admin-undo-repo.ts +128 -0
- package/src/announcement-repo.ts +176 -0
- package/src/antispam-repo.ts +145 -0
- package/src/api-repo.ts +276 -0
- package/src/attachment-admin-repo.ts +161 -0
- package/src/attachment-repo.ts +240 -0
- package/src/authorization-source.ts +138 -0
- package/src/avatar-repo.ts +185 -0
- package/src/ban-repos.ts +146 -0
- package/src/client.ts +85 -0
- package/src/content-admin-repo.ts +298 -0
- package/src/content-counters.ts +152 -0
- package/src/counter-recount.ts +263 -0
- package/src/cursor.ts +16 -0
- package/src/denormalised-username.ts +34 -0
- package/src/discovery-repo.ts +140 -0
- package/src/draft-repo.ts +59 -0
- package/src/feed-repo.ts +219 -0
- package/src/forum-admin-repo.ts +310 -0
- package/src/forum-repo.ts +206 -0
- package/src/group-admin-repo.ts +256 -0
- package/src/group-identity-repo.ts +84 -0
- package/src/identity-link-repo.ts +145 -0
- package/src/import-repo.ts +123 -0
- package/src/import-sink.ts +1377 -0
- package/src/index.ts +316 -0
- package/src/inline-moderation.ts +344 -0
- package/src/install-repo.ts +67 -0
- package/src/latest-repo.ts +115 -0
- package/src/maintenance-repo.ts +54 -0
- package/src/marketplace-repo.ts +111 -0
- package/src/member-profile-repo.ts +82 -0
- package/src/member-settings-repo.ts +160 -0
- package/src/message-repo.ts +384 -0
- package/src/migrate-run.ts +18 -0
- package/src/migrate.ts +129 -0
- package/src/modcp-repo.ts +253 -0
- package/src/moderation-queue.ts +279 -0
- package/src/navigation-repo.ts +288 -0
- package/src/notification-repo.ts +402 -0
- package/src/orphan-keys.ts +19 -0
- package/src/outbox-repo.ts +78 -0
- package/src/permission-version.ts +24 -0
- package/src/permissions-map.ts +52 -0
- package/src/pglite.fixture.ts +87 -0
- package/src/plugin-data.ts +88 -0
- package/src/plugin-grants.ts +369 -0
- package/src/plugin-health-repo.ts +80 -0
- package/src/plugin-purge-repo.ts +91 -0
- package/src/plugin-users.ts +39 -0
- package/src/poll-repo.ts +334 -0
- package/src/post-repo.ts +261 -0
- package/src/post-writes.ts +227 -0
- package/src/presence-repo.ts +220 -0
- package/src/profile-field-repo.ts +182 -0
- package/src/promotion-repo.ts +152 -0
- package/src/read-state-repo.ts +81 -0
- package/src/relation-repo.ts +113 -0
- package/src/render-backfill.ts +110 -0
- package/src/render-signature.ts +33 -0
- package/src/report-repo.ts +349 -0
- package/src/reputation-repo.ts +295 -0
- package/src/result-rows.ts +13 -0
- package/src/row-values.ts +7 -0
- package/src/schema/content.ts +451 -0
- package/src/schema/identity.ts +699 -0
- package/src/schema/index.ts +10 -0
- package/src/schema/messages.ts +76 -0
- package/src/schema/permission-columns.ts +34 -0
- package/src/schema/platform.ts +376 -0
- package/src/schema/structure.ts +164 -0
- package/src/search-repo.ts +359 -0
- package/src/search-store.ts +113 -0
- package/src/seed-groups.ts +11 -0
- package/src/settings-repo.ts +32 -0
- package/src/signature-repo.ts +102 -0
- package/src/sql-lists.ts +17 -0
- package/src/staff-groups.ts +50 -0
- package/src/stats-repo.ts +151 -0
- package/src/subscription-repo.ts +350 -0
- package/src/system-health-repo.ts +130 -0
- package/src/task-repo.ts +104 -0
- package/src/theme-admin-repo.ts +172 -0
- package/src/theme-repo.ts +43 -0
- package/src/thread-audience.ts +45 -0
- package/src/thread-counters.ts +107 -0
- package/src/thread-repo.ts +255 -0
- package/src/thread-surgery.ts +282 -0
- package/src/thread-tools.ts +311 -0
- package/src/thread-views.ts +41 -0
- package/src/thread-writes.ts +356 -0
- package/src/two-factor-repo.ts +235 -0
- package/src/upgrade-repo.ts +66 -0
- package/src/user-admin-repo.ts +367 -0
- package/src/user-bulk-repo.ts +397 -0
- package/src/user-merge-map.ts +111 -0
- package/src/user-merge-repo.ts +304 -0
- package/src/visibility-counters.ts +190 -0
- package/src/visibility.ts +17 -0
- package/src/vocabulary-repo.ts +54 -0
- package/src/warning-repo.ts +328 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createPostgresAccountStore,
|
|
3
|
+
PostgresAccountRepository,
|
|
4
|
+
PostgresCredentialTokenRepository,
|
|
5
|
+
PostgresLoginAttemptRepository,
|
|
6
|
+
PostgresRememberTokenRepository,
|
|
7
|
+
PostgresSessionRepository,
|
|
8
|
+
} from './account-repos'
|
|
9
|
+
export { ActorBuilder, type ActorBuilderConfig } from './actor-builder'
|
|
10
|
+
export {
|
|
11
|
+
type GroupSummary,
|
|
12
|
+
PostgresAdminRepository,
|
|
13
|
+
type UserSummary,
|
|
14
|
+
} from './admin-repo'
|
|
15
|
+
export {
|
|
16
|
+
PostgresAdminLogRepository,
|
|
17
|
+
PostgresAdminSessionRepository,
|
|
18
|
+
} from './admin-session-repo'
|
|
19
|
+
export {
|
|
20
|
+
ADMIN_UNDO_MAX_SNAPSHOT_BYTES,
|
|
21
|
+
type AdminUndoOperation,
|
|
22
|
+
PostgresAdminUndoRepository,
|
|
23
|
+
} from './admin-undo-repo'
|
|
24
|
+
export {
|
|
25
|
+
type AnnouncementInput,
|
|
26
|
+
type AnnouncementRow,
|
|
27
|
+
PostgresAnnouncementRepository,
|
|
28
|
+
} from './announcement-repo'
|
|
29
|
+
export {
|
|
30
|
+
type CaptchaQuestionRow,
|
|
31
|
+
PostgresCaptchaQuestionRepository,
|
|
32
|
+
PostgresRateLimitBucketStore,
|
|
33
|
+
} from './antispam-repo'
|
|
34
|
+
export {
|
|
35
|
+
type ApiTokenSummary,
|
|
36
|
+
PostgresApiTokenRepository,
|
|
37
|
+
PostgresRateLimitStore,
|
|
38
|
+
PostgresWebhookRepository,
|
|
39
|
+
type WebhookDeliveryRow,
|
|
40
|
+
} from './api-repo'
|
|
41
|
+
export {
|
|
42
|
+
type AttachmentAdminFilter,
|
|
43
|
+
type AttachmentAdminPage,
|
|
44
|
+
type AttachmentAdminRow,
|
|
45
|
+
type AttachmentTotals,
|
|
46
|
+
PostgresAttachmentAdminRepository,
|
|
47
|
+
} from './attachment-admin-repo'
|
|
48
|
+
export { PostgresAttachmentRepository } from './attachment-repo'
|
|
49
|
+
export {
|
|
50
|
+
PostgresAuthorizationSource,
|
|
51
|
+
parseAncestorPath,
|
|
52
|
+
} from './authorization-source'
|
|
53
|
+
export { PostgresAvatarRepository } from './avatar-repo'
|
|
54
|
+
export {
|
|
55
|
+
PostgresBanFilterRepository,
|
|
56
|
+
PostgresBanRepository,
|
|
57
|
+
} from './ban-repos'
|
|
58
|
+
export {
|
|
59
|
+
closeDb,
|
|
60
|
+
createIsolatedDb,
|
|
61
|
+
type Database,
|
|
62
|
+
getDb,
|
|
63
|
+
schema,
|
|
64
|
+
} from './client'
|
|
65
|
+
export {
|
|
66
|
+
type DirectiveRow,
|
|
67
|
+
PostgresContentAdminRepository,
|
|
68
|
+
type SmileyRow,
|
|
69
|
+
type ThreadPrefixRow,
|
|
70
|
+
type WordFilterRow,
|
|
71
|
+
} from './content-admin-repo'
|
|
72
|
+
export {
|
|
73
|
+
applyCreatedContentCounters,
|
|
74
|
+
type CreatedContent,
|
|
75
|
+
PostgresContentCounterRepository,
|
|
76
|
+
rollUpAncestorCounters,
|
|
77
|
+
} from './content-counters'
|
|
78
|
+
export {
|
|
79
|
+
PostgresCounterRecount,
|
|
80
|
+
RECOUNT_PHASES,
|
|
81
|
+
type RecountPhase,
|
|
82
|
+
type RecountRun,
|
|
83
|
+
} from './counter-recount'
|
|
84
|
+
export {
|
|
85
|
+
type DiscoveryPage,
|
|
86
|
+
type DiscoveryQuery,
|
|
87
|
+
type DiscoveryRow,
|
|
88
|
+
type DiscoveryScope,
|
|
89
|
+
PostgresDiscoveryRepository,
|
|
90
|
+
} from './discovery-repo'
|
|
91
|
+
export { PostgresDraftRepository } from './draft-repo'
|
|
92
|
+
export {
|
|
93
|
+
type FeedPost,
|
|
94
|
+
type FeedScope,
|
|
95
|
+
type FeedThread,
|
|
96
|
+
PostgresFeedRepository,
|
|
97
|
+
type SitemapForum,
|
|
98
|
+
type SitemapThread,
|
|
99
|
+
} from './feed-repo'
|
|
100
|
+
export {
|
|
101
|
+
type AppointModeratorInput,
|
|
102
|
+
type ForumOptionsInput,
|
|
103
|
+
MODERATOR_RIGHTS,
|
|
104
|
+
type ModeratorAppointmentRow,
|
|
105
|
+
type ModeratorRight,
|
|
106
|
+
PostgresForumAdminRepository,
|
|
107
|
+
} from './forum-admin-repo'
|
|
108
|
+
export { PostgresForumRepository } from './forum-repo'
|
|
109
|
+
export {
|
|
110
|
+
type GroupIdentityInput,
|
|
111
|
+
type GroupSummaryRow,
|
|
112
|
+
type MembershipChunkResult,
|
|
113
|
+
PostgresGroupAdminRepository,
|
|
114
|
+
} from './group-admin-repo'
|
|
115
|
+
export {
|
|
116
|
+
type GroupIdentity,
|
|
117
|
+
type MemberStanding,
|
|
118
|
+
PostgresGroupIdentityRepository,
|
|
119
|
+
} from './group-identity-repo'
|
|
120
|
+
export {
|
|
121
|
+
PostgresPasskeyRepository,
|
|
122
|
+
PostgresUserIdentityRepository,
|
|
123
|
+
} from './identity-link-repo'
|
|
124
|
+
export {
|
|
125
|
+
currentImportRun,
|
|
126
|
+
finishImportRun,
|
|
127
|
+
type ImportRunRow,
|
|
128
|
+
type ImportSourceName,
|
|
129
|
+
type LegacyKind,
|
|
130
|
+
mapLegacyId,
|
|
131
|
+
resolveLegacyId,
|
|
132
|
+
resolveLegacyIds,
|
|
133
|
+
saveImportProgress,
|
|
134
|
+
startImportRun,
|
|
135
|
+
} from './import-repo'
|
|
136
|
+
export {
|
|
137
|
+
type CopiedAttachment,
|
|
138
|
+
type CopiedAvatar,
|
|
139
|
+
type ImportFileCopier,
|
|
140
|
+
PostgresImportSink,
|
|
141
|
+
} from './import-sink'
|
|
142
|
+
export { PostgresInlineModerationRepository } from './inline-moderation'
|
|
143
|
+
export {
|
|
144
|
+
canConnect,
|
|
145
|
+
countUsers,
|
|
146
|
+
INSTALL_LOCK_KEY,
|
|
147
|
+
isInstalled,
|
|
148
|
+
markInstalled,
|
|
149
|
+
withInstallLock,
|
|
150
|
+
} from './install-repo'
|
|
151
|
+
export {
|
|
152
|
+
type LatestPostRow,
|
|
153
|
+
type LatestScope,
|
|
154
|
+
type LatestThreadRow,
|
|
155
|
+
PostgresLatestRepository,
|
|
156
|
+
} from './latest-repo'
|
|
157
|
+
export { PostgresMaintenanceRepository } from './maintenance-repo'
|
|
158
|
+
export { PostgresMarketplaceCacheRepository } from './marketplace-repo'
|
|
159
|
+
export { PostgresMemberProfileRepository } from './member-profile-repo'
|
|
160
|
+
export { PostgresMemberSettingsRepository } from './member-settings-repo'
|
|
161
|
+
export { PostgresMessageRepository } from './message-repo'
|
|
162
|
+
export { migrationUrl, runMigrations } from './migrate'
|
|
163
|
+
export { PostgresModCpRepository } from './modcp-repo'
|
|
164
|
+
export { PostgresModerationQueueRepository } from './moderation-queue'
|
|
165
|
+
export {
|
|
166
|
+
type NavigationAudience,
|
|
167
|
+
type NavigationDropTarget,
|
|
168
|
+
type NavigationItemInput,
|
|
169
|
+
type NavigationItemRow,
|
|
170
|
+
type PluginNavigationRow,
|
|
171
|
+
PostgresNavigationRepository,
|
|
172
|
+
} from './navigation-repo'
|
|
173
|
+
export { PostgresNotificationRepository } from './notification-repo'
|
|
174
|
+
export { PostgresOutboxReader } from './outbox-repo'
|
|
175
|
+
export {
|
|
176
|
+
forumRowToOverride,
|
|
177
|
+
groupRowToPermissionSet,
|
|
178
|
+
type PermissionRow,
|
|
179
|
+
} from './permissions-map'
|
|
180
|
+
export { bindPluginSql, pluginData } from './plugin-data'
|
|
181
|
+
export {
|
|
182
|
+
expireTimedGroupMemberships,
|
|
183
|
+
PLUGIN_UNGRANTABLE_PERMISSIONS,
|
|
184
|
+
permissionsCarryPower,
|
|
185
|
+
pluginGrants,
|
|
186
|
+
} from './plugin-grants'
|
|
187
|
+
export {
|
|
188
|
+
clearPluginHealth,
|
|
189
|
+
type PluginHealthRecord,
|
|
190
|
+
readPluginHealth,
|
|
191
|
+
recordPluginFailure,
|
|
192
|
+
} from './plugin-health-repo'
|
|
193
|
+
export {
|
|
194
|
+
type PluginPurgeResult,
|
|
195
|
+
pluginOwnedTables,
|
|
196
|
+
purgePlugin,
|
|
197
|
+
} from './plugin-purge-repo'
|
|
198
|
+
export { pluginUsers } from './plugin-users'
|
|
199
|
+
export { PostgresPollRepository } from './poll-repo'
|
|
200
|
+
export { PostgresPostRepository } from './post-repo'
|
|
201
|
+
export { PostgresPostWriteRepository } from './post-writes'
|
|
202
|
+
export {
|
|
203
|
+
ONLINE_WINDOW_MINUTES,
|
|
204
|
+
type OnlineMember,
|
|
205
|
+
type OnlineRecord,
|
|
206
|
+
type OnlineScope,
|
|
207
|
+
type OnlineSnapshot,
|
|
208
|
+
PostgresPresenceRepository,
|
|
209
|
+
} from './presence-repo'
|
|
210
|
+
export { PostgresProfileFieldRepository } from './profile-field-repo'
|
|
211
|
+
export { PostgresPromotionRepository } from './promotion-repo'
|
|
212
|
+
export { PostgresReadStateRepository } from './read-state-repo'
|
|
213
|
+
export { PostgresRelationRepository } from './relation-repo'
|
|
214
|
+
export {
|
|
215
|
+
PostgresRenderBackfill,
|
|
216
|
+
type RenderBackfillRun,
|
|
217
|
+
} from './render-backfill'
|
|
218
|
+
export { syncRenderSignature } from './render-signature'
|
|
219
|
+
export { PostgresReportRepository } from './report-repo'
|
|
220
|
+
export { PostgresReputationRepository } from './reputation-repo'
|
|
221
|
+
export { resultRows } from './result-rows'
|
|
222
|
+
export * from './schema'
|
|
223
|
+
export {
|
|
224
|
+
indexedSubjectSql,
|
|
225
|
+
PostgresSearchRepository,
|
|
226
|
+
type ReindexResult,
|
|
227
|
+
SEARCH_DOCUMENT_VERSION,
|
|
228
|
+
SEARCH_WINDOW,
|
|
229
|
+
searchVectorSql,
|
|
230
|
+
} from './search-repo'
|
|
231
|
+
export {
|
|
232
|
+
type CreateSearchInput,
|
|
233
|
+
ownsSearch,
|
|
234
|
+
PostgresSearchStore,
|
|
235
|
+
type StoredSearch,
|
|
236
|
+
} from './search-store'
|
|
237
|
+
export { SEED_GROUP_KEY, type SeedGroupKey } from './seed-groups'
|
|
238
|
+
export { PostgresSettingsRepository } from './settings-repo'
|
|
239
|
+
export { PostgresSignatureRepository } from './signature-repo'
|
|
240
|
+
export {
|
|
241
|
+
type BoardTotals,
|
|
242
|
+
PostgresStatsRepository,
|
|
243
|
+
type StatsScope,
|
|
244
|
+
type TopPoster,
|
|
245
|
+
type TopThread,
|
|
246
|
+
} from './stats-repo'
|
|
247
|
+
export { PostgresSubscriptionRepository } from './subscription-repo'
|
|
248
|
+
export {
|
|
249
|
+
type BoardVolumes,
|
|
250
|
+
PostgresSystemHealthRepository,
|
|
251
|
+
type RecountStateRow,
|
|
252
|
+
type TaskRunRow,
|
|
253
|
+
} from './system-health-repo'
|
|
254
|
+
export { PostgresTaskRepository } from './task-repo'
|
|
255
|
+
export {
|
|
256
|
+
PostgresThemeAdminRepository,
|
|
257
|
+
parseThemeExport,
|
|
258
|
+
type ThemeExport,
|
|
259
|
+
type ThemeRecord,
|
|
260
|
+
} from './theme-admin-repo'
|
|
261
|
+
export {
|
|
262
|
+
PostgresThemeRepository,
|
|
263
|
+
type ThemeRuntimeRecord,
|
|
264
|
+
type ThemeRuntimeState,
|
|
265
|
+
} from './theme-repo'
|
|
266
|
+
export { PostgresThreadRepository } from './thread-repo'
|
|
267
|
+
export { PostgresThreadSurgeryRepository } from './thread-surgery'
|
|
268
|
+
export { PostgresThreadToolsRepository } from './thread-tools'
|
|
269
|
+
export { PostgresThreadViewBuffer } from './thread-views'
|
|
270
|
+
export { PostgresThreadWriteRepository } from './thread-writes'
|
|
271
|
+
export {
|
|
272
|
+
PostgresAuthEventRepository,
|
|
273
|
+
PostgresRecoveryCodeRepository,
|
|
274
|
+
PostgresTwoFactorRepository,
|
|
275
|
+
} from './two-factor-repo'
|
|
276
|
+
export {
|
|
277
|
+
appliedPluginMigrations,
|
|
278
|
+
applyPluginMigration,
|
|
279
|
+
readVersion,
|
|
280
|
+
readVersions,
|
|
281
|
+
recordVersion,
|
|
282
|
+
} from './upgrade-repo'
|
|
283
|
+
export {
|
|
284
|
+
type AccountState,
|
|
285
|
+
likeFragment,
|
|
286
|
+
PostgresUserAdminRepository,
|
|
287
|
+
type UserAccountInput,
|
|
288
|
+
type UserDetail,
|
|
289
|
+
type UserSearchFilter,
|
|
290
|
+
type UserSearchPage,
|
|
291
|
+
type UserSearchRow,
|
|
292
|
+
} from './user-admin-repo'
|
|
293
|
+
export {
|
|
294
|
+
type MassMailChunk,
|
|
295
|
+
type MassMailRecipient,
|
|
296
|
+
type MassMailRow,
|
|
297
|
+
PostgresUserBulkRepository,
|
|
298
|
+
type PruneChunkResult,
|
|
299
|
+
type PruneCriteria,
|
|
300
|
+
type PrunePreview,
|
|
301
|
+
} from './user-bulk-repo'
|
|
302
|
+
export { mergeMapColumns } from './user-merge-map'
|
|
303
|
+
export {
|
|
304
|
+
type MergeChunkResult,
|
|
305
|
+
type MergePreview,
|
|
306
|
+
PostgresUserMergeRepository,
|
|
307
|
+
} from './user-merge-repo'
|
|
308
|
+
export {
|
|
309
|
+
applyAncestorVisibilityChange,
|
|
310
|
+
applyVisibilityChangeCounters,
|
|
311
|
+
repairForumLastPostChain,
|
|
312
|
+
repairThreadLastPost,
|
|
313
|
+
type VisibilityChange,
|
|
314
|
+
} from './visibility-counters'
|
|
315
|
+
export { readBoardVocabulary, readVocabularySource } from './vocabulary-repo'
|
|
316
|
+
export { PostgresWarningRepository } from './warning-repo'
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
InlineModerationRepository,
|
|
5
|
+
InlineTarget,
|
|
6
|
+
InlineTool,
|
|
7
|
+
MoveDestination,
|
|
8
|
+
QueueSelection,
|
|
9
|
+
} from '@meith/moderation'
|
|
10
|
+
|
|
11
|
+
import type { Database } from './client'
|
|
12
|
+
import { resultRows } from './result-rows'
|
|
13
|
+
import { idList } from './sql-lists'
|
|
14
|
+
import {
|
|
15
|
+
applyAuthorCounts,
|
|
16
|
+
applyForumChain,
|
|
17
|
+
type CounterTx,
|
|
18
|
+
logModeratorAction,
|
|
19
|
+
syncLedger,
|
|
20
|
+
tallyThread,
|
|
21
|
+
} from './thread-counters'
|
|
22
|
+
import { PENDING_APPROVAL } from './visibility'
|
|
23
|
+
import { applyVisibilityChangeCounters, repairForumLastPostChain } from './visibility-counters'
|
|
24
|
+
|
|
25
|
+
interface TargetRow {
|
|
26
|
+
kind: 'thread' | 'post'
|
|
27
|
+
id: number
|
|
28
|
+
forum_id: number
|
|
29
|
+
visibility: InlineTarget['visibility']
|
|
30
|
+
thread_visibility: InlineTarget['visibility']
|
|
31
|
+
is_locked: boolean
|
|
32
|
+
is_sticky: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class PostgresInlineModerationRepository implements InlineModerationRepository {
|
|
36
|
+
constructor(private readonly db: Database) {}
|
|
37
|
+
|
|
38
|
+
async resolve(
|
|
39
|
+
selection: readonly QueueSelection[],
|
|
40
|
+
forumIds: readonly number[],
|
|
41
|
+
): Promise<readonly InlineTarget[]> {
|
|
42
|
+
if (forumIds.length === 0) return []
|
|
43
|
+
const threadIds = selection.filter((s) => s.kind === 'thread').map((s) => s.id)
|
|
44
|
+
const postIds = selection.filter((s) => s.kind === 'post').map((s) => s.id)
|
|
45
|
+
if (threadIds.length === 0 && postIds.length === 0) return []
|
|
46
|
+
|
|
47
|
+
const rows = resultRows(
|
|
48
|
+
await this.db.execute(sql`
|
|
49
|
+
select 'thread'::text as kind, t.id, t.forum_id, t.visibility,
|
|
50
|
+
t.visibility as thread_visibility, t.is_locked, t.is_sticky
|
|
51
|
+
from threads t
|
|
52
|
+
where t.id in ${idList(threadIds)}
|
|
53
|
+
and t.forum_id in ${idList(forumIds)}
|
|
54
|
+
union all
|
|
55
|
+
select 'post'::text, p.id, t.forum_id, p.visibility,
|
|
56
|
+
t.visibility as thread_visibility, false, false
|
|
57
|
+
from posts p
|
|
58
|
+
join threads t on t.id = p.thread_id
|
|
59
|
+
where p.id in ${idList(postIds)}
|
|
60
|
+
and t.forum_id in ${idList(forumIds)}
|
|
61
|
+
`),
|
|
62
|
+
) as TargetRow[]
|
|
63
|
+
|
|
64
|
+
return rows.map((row) => ({
|
|
65
|
+
kind: row.kind,
|
|
66
|
+
id: Number(row.id),
|
|
67
|
+
forumId: Number(row.forum_id),
|
|
68
|
+
visibility: row.visibility,
|
|
69
|
+
threadVisibility: row.thread_visibility,
|
|
70
|
+
isLocked: row.is_locked,
|
|
71
|
+
isSticky: row.is_sticky,
|
|
72
|
+
}))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async findDestination(forumId: number): Promise<MoveDestination | null> {
|
|
76
|
+
const rows = resultRows(
|
|
77
|
+
await this.db.execute(sql`select id, type, allow_threads from forums where id = ${forumId}`),
|
|
78
|
+
) as Array<{ id: number; type: MoveDestination['type']; allow_threads: boolean }>
|
|
79
|
+
const row = rows[0]
|
|
80
|
+
return row === undefined
|
|
81
|
+
? null
|
|
82
|
+
: { id: Number(row.id), type: row.type, allowThreads: row.allow_threads === true }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async apply(input: {
|
|
86
|
+
readonly tool: InlineTool
|
|
87
|
+
readonly threadIds: readonly number[]
|
|
88
|
+
readonly postIds: readonly number[]
|
|
89
|
+
readonly toForumId?: number | undefined
|
|
90
|
+
readonly actorUserId: number
|
|
91
|
+
readonly at: Date
|
|
92
|
+
}): Promise<number> {
|
|
93
|
+
if (input.threadIds.length === 0 && input.postIds.length === 0) return 0
|
|
94
|
+
|
|
95
|
+
return this.db.transaction(async (tx) => {
|
|
96
|
+
let applied = 0
|
|
97
|
+
const touched = await forumsOf(tx, input.threadIds, input.postIds)
|
|
98
|
+
|
|
99
|
+
switch (input.tool) {
|
|
100
|
+
case 'lock':
|
|
101
|
+
case 'unlock':
|
|
102
|
+
case 'stick':
|
|
103
|
+
case 'unstick':
|
|
104
|
+
applied = await flagThreads(tx, input.tool, input.threadIds, input.at)
|
|
105
|
+
break
|
|
106
|
+
|
|
107
|
+
case 'approve':
|
|
108
|
+
for (const threadId of input.threadIds) {
|
|
109
|
+
applied += (await approveThread(tx, threadId)) ? 1 : 0
|
|
110
|
+
}
|
|
111
|
+
for (const postId of input.postIds) {
|
|
112
|
+
applied += (await movePost(tx, postId, PENDING_APPROVAL, 'visible')) ? 1 : 0
|
|
113
|
+
}
|
|
114
|
+
break
|
|
115
|
+
|
|
116
|
+
case 'delete':
|
|
117
|
+
case 'restore': {
|
|
118
|
+
const from = input.tool === 'delete' ? 'visible' : 'deleted'
|
|
119
|
+
const to = input.tool === 'delete' ? 'deleted' : 'visible'
|
|
120
|
+
for (const threadId of input.threadIds) {
|
|
121
|
+
applied += (await setThreadVisibility(tx, threadId, from, to, input.at)) ? 1 : 0
|
|
122
|
+
}
|
|
123
|
+
for (const postId of input.postIds) {
|
|
124
|
+
applied += (await movePost(tx, postId, from, to)) ? 1 : 0
|
|
125
|
+
}
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
case 'move': {
|
|
130
|
+
if (input.toForumId === undefined) return 0
|
|
131
|
+
for (const threadId of input.threadIds) {
|
|
132
|
+
applied += (await moveThread(tx, threadId, input.toForumId, input.at)) ? 1 : 0
|
|
133
|
+
}
|
|
134
|
+
break
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (applied > 0) {
|
|
139
|
+
await logModeratorAction(
|
|
140
|
+
tx,
|
|
141
|
+
`inline.${input.tool}`,
|
|
142
|
+
input.actorUserId,
|
|
143
|
+
{
|
|
144
|
+
threadIds: input.threadIds,
|
|
145
|
+
postIds: input.postIds,
|
|
146
|
+
applied,
|
|
147
|
+
...forumKeys([...touched], input.toForumId),
|
|
148
|
+
},
|
|
149
|
+
input.at,
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return applied
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function forumsOf(
|
|
159
|
+
tx: CounterTx,
|
|
160
|
+
threadIds: readonly number[],
|
|
161
|
+
postIds: readonly number[],
|
|
162
|
+
): Promise<ReadonlySet<number>> {
|
|
163
|
+
const rows = resultRows(
|
|
164
|
+
await tx.execute(sql`
|
|
165
|
+
select forum_id from threads where id in ${idList(threadIds)}
|
|
166
|
+
union
|
|
167
|
+
select forum_id from posts where id in ${idList(postIds)}
|
|
168
|
+
`),
|
|
169
|
+
) as Array<{ forum_id: number }>
|
|
170
|
+
return new Set(rows.map((row) => Number(row.forum_id)))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function forumKeys(
|
|
174
|
+
source: readonly number[],
|
|
175
|
+
toForumId: number | undefined,
|
|
176
|
+
): Record<string, unknown> {
|
|
177
|
+
if (toForumId === undefined) {
|
|
178
|
+
return source.length === 1 ? { forumId: source[0], forumIds: source } : { forumIds: source }
|
|
179
|
+
}
|
|
180
|
+
const forumIds = [...new Set([...source, toForumId])]
|
|
181
|
+
return source.length === 1
|
|
182
|
+
? { fromForumId: source[0], toForumId, forumIds }
|
|
183
|
+
: { toForumId, forumIds }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function flagThreads(
|
|
187
|
+
tx: CounterTx,
|
|
188
|
+
tool: 'lock' | 'unlock' | 'stick' | 'unstick',
|
|
189
|
+
threadIds: readonly number[],
|
|
190
|
+
at: Date,
|
|
191
|
+
): Promise<number> {
|
|
192
|
+
if (threadIds.length === 0) return 0
|
|
193
|
+
const locking = tool === 'lock' || tool === 'unlock'
|
|
194
|
+
const value = tool === 'lock' || tool === 'stick'
|
|
195
|
+
|
|
196
|
+
const moved = resultRows(
|
|
197
|
+
await tx.execute(
|
|
198
|
+
locking
|
|
199
|
+
? sql`update threads set is_locked = ${value}, updated_at = ${at}
|
|
200
|
+
where id in ${idList(threadIds)} and visibility = 'visible'
|
|
201
|
+
and is_locked <> ${value} returning id`
|
|
202
|
+
: sql`update threads set is_sticky = ${value}, updated_at = ${at}
|
|
203
|
+
where id in ${idList(threadIds)} and visibility = 'visible'
|
|
204
|
+
and is_sticky <> ${value} returning id`,
|
|
205
|
+
),
|
|
206
|
+
) as Array<{ id: number }>
|
|
207
|
+
return moved.length
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function approveThread(tx: CounterTx, threadId: number): Promise<boolean> {
|
|
211
|
+
const moved = resultRows(
|
|
212
|
+
await tx.execute(sql`
|
|
213
|
+
update threads set visibility = 'visible', updated_at = now()
|
|
214
|
+
where id = ${threadId} and visibility = ${PENDING_APPROVAL}
|
|
215
|
+
returning id, forum_id, first_post_id, author_user_id
|
|
216
|
+
`),
|
|
217
|
+
) as Array<{
|
|
218
|
+
id: number
|
|
219
|
+
forum_id: number
|
|
220
|
+
first_post_id: number | null
|
|
221
|
+
author_user_id: number | null
|
|
222
|
+
}>
|
|
223
|
+
const thread = moved[0]
|
|
224
|
+
if (!thread) return false
|
|
225
|
+
|
|
226
|
+
if (thread.first_post_id !== null) {
|
|
227
|
+
const post = resultRows(
|
|
228
|
+
await tx.execute(sql`
|
|
229
|
+
update posts set visibility = 'visible'
|
|
230
|
+
where id = ${thread.first_post_id} and visibility = ${PENDING_APPROVAL}
|
|
231
|
+
returning id
|
|
232
|
+
`),
|
|
233
|
+
) as Array<{ id: number }>
|
|
234
|
+
|
|
235
|
+
if (post[0]) {
|
|
236
|
+
await applyVisibilityChangeCounters(tx, {
|
|
237
|
+
postId: Number(post[0].id),
|
|
238
|
+
threadId: Number(thread.id),
|
|
239
|
+
forumId: Number(thread.forum_id),
|
|
240
|
+
authorId: thread.author_user_id === null ? null : Number(thread.author_user_id),
|
|
241
|
+
isFirstPost: true,
|
|
242
|
+
delta: 1,
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return true
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function movePost(tx: CounterTx, postId: number, from: string, to: string): Promise<boolean> {
|
|
250
|
+
const moved = resultRows(
|
|
251
|
+
await tx.execute(sql`
|
|
252
|
+
update posts set visibility = ${to}
|
|
253
|
+
where id = ${postId} and visibility = ${from}
|
|
254
|
+
returning id, thread_id, forum_id, author_user_id, is_first_post
|
|
255
|
+
`),
|
|
256
|
+
) as Array<{
|
|
257
|
+
id: number
|
|
258
|
+
thread_id: number
|
|
259
|
+
forum_id: number
|
|
260
|
+
author_user_id: number | null
|
|
261
|
+
is_first_post: boolean
|
|
262
|
+
}>
|
|
263
|
+
const post = moved[0]
|
|
264
|
+
if (!post) return false
|
|
265
|
+
|
|
266
|
+
const delta = (to === 'visible' ? 1 : 0) - (from === 'visible' ? 1 : 0)
|
|
267
|
+
if (delta !== 0) {
|
|
268
|
+
await applyVisibilityChangeCounters(tx, {
|
|
269
|
+
postId: Number(post.id),
|
|
270
|
+
threadId: Number(post.thread_id),
|
|
271
|
+
forumId: Number(post.forum_id),
|
|
272
|
+
authorId: post.author_user_id === null ? null : Number(post.author_user_id),
|
|
273
|
+
isFirstPost: post.is_first_post,
|
|
274
|
+
delta: delta as 1 | -1,
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
return true
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function setThreadVisibility(
|
|
281
|
+
tx: CounterTx,
|
|
282
|
+
threadId: number,
|
|
283
|
+
from: 'visible' | 'deleted',
|
|
284
|
+
to: 'visible' | 'deleted',
|
|
285
|
+
at: Date,
|
|
286
|
+
): Promise<boolean> {
|
|
287
|
+
const tally = await tallyThread(tx, threadId)
|
|
288
|
+
|
|
289
|
+
const moved = resultRows(
|
|
290
|
+
await tx.execute(sql`
|
|
291
|
+
update threads set visibility = ${to}, updated_at = ${at}
|
|
292
|
+
where id = ${threadId} and visibility = ${from}
|
|
293
|
+
returning forum_id
|
|
294
|
+
`),
|
|
295
|
+
) as Array<{ forum_id: number }>
|
|
296
|
+
const row = moved[0]
|
|
297
|
+
if (!row) return false
|
|
298
|
+
|
|
299
|
+
const forumId = Number(row.forum_id)
|
|
300
|
+
const delta: 1 | -1 = to === 'visible' ? 1 : -1
|
|
301
|
+
|
|
302
|
+
await applyForumChain(tx, forumId, delta, tally)
|
|
303
|
+
await applyAuthorCounts(tx, delta, tally)
|
|
304
|
+
await syncLedger(tx, threadId, to === 'visible')
|
|
305
|
+
await repairForumLastPostChain(tx, forumId)
|
|
306
|
+
return true
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async function moveThread(
|
|
310
|
+
tx: CounterTx,
|
|
311
|
+
threadId: number,
|
|
312
|
+
toForumId: number,
|
|
313
|
+
at: Date,
|
|
314
|
+
): Promise<boolean> {
|
|
315
|
+
const current = resultRows(
|
|
316
|
+
await tx.execute(sql`select forum_id, visibility from threads where id = ${threadId}`),
|
|
317
|
+
) as Array<{ forum_id: number; visibility: string }>
|
|
318
|
+
const before = current[0]
|
|
319
|
+
if (before?.visibility !== 'visible') return false
|
|
320
|
+
|
|
321
|
+
const fromForumId = Number(before.forum_id)
|
|
322
|
+
if (fromForumId === toForumId) return false
|
|
323
|
+
|
|
324
|
+
const tally = await tallyThread(tx, threadId)
|
|
325
|
+
|
|
326
|
+
const moved = resultRows(
|
|
327
|
+
await tx.execute(sql`
|
|
328
|
+
update threads set forum_id = ${toForumId}, updated_at = ${at}
|
|
329
|
+
where id = ${threadId} and forum_id = ${fromForumId}
|
|
330
|
+
returning id
|
|
331
|
+
`),
|
|
332
|
+
) as Array<{ id: number }>
|
|
333
|
+
if (moved.length === 0) return false
|
|
334
|
+
|
|
335
|
+
await tx.execute(sql`
|
|
336
|
+
update posts set forum_id = ${toForumId} where thread_id = ${threadId}
|
|
337
|
+
`)
|
|
338
|
+
|
|
339
|
+
await applyForumChain(tx, fromForumId, -1, tally)
|
|
340
|
+
await applyForumChain(tx, toForumId, 1, tally)
|
|
341
|
+
await repairForumLastPostChain(tx, fromForumId)
|
|
342
|
+
await repairForumLastPostChain(tx, toForumId)
|
|
343
|
+
return true
|
|
344
|
+
}
|