@meith/import 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/package.json +24 -0
- package/src/index.ts +130 -0
- package/src/legacy-urls.ts +131 -0
- package/src/map.ts +297 -0
- package/src/memory-sink.fixture.ts +64 -0
- package/src/mybb-fixture.ts +185 -0
- package/src/mybb-rows.ts +172 -0
- package/src/mysql-source.ts +391 -0
- package/src/phpbb-fixture.ts +191 -0
- package/src/phpbb-map.ts +297 -0
- package/src/phpbb-mysql-source.ts +355 -0
- package/src/phpbb-rows.ts +160 -0
- package/src/phpbb-text.ts +44 -0
- package/src/run.ts +261 -0
- package/src/source.ts +98 -0
- package/src/types.ts +176 -0
package/src/map.ts
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MybbAttachment,
|
|
3
|
+
MybbAvatarRow,
|
|
4
|
+
MybbBan,
|
|
5
|
+
MybbForum,
|
|
6
|
+
MybbForumSubscription,
|
|
7
|
+
MybbPoll,
|
|
8
|
+
MybbPollVote,
|
|
9
|
+
MybbPost,
|
|
10
|
+
MybbPrivateMessage,
|
|
11
|
+
MybbRelationList,
|
|
12
|
+
MybbReputation,
|
|
13
|
+
MybbThread,
|
|
14
|
+
MybbThreadSubscription,
|
|
15
|
+
MybbUser,
|
|
16
|
+
MybbWarning,
|
|
17
|
+
} from './mybb-rows'
|
|
18
|
+
import type {
|
|
19
|
+
ImportedAttachment,
|
|
20
|
+
ImportedAvatar,
|
|
21
|
+
ImportedBan,
|
|
22
|
+
ImportedForum,
|
|
23
|
+
ImportedPoll,
|
|
24
|
+
ImportedPollVote,
|
|
25
|
+
ImportedPost,
|
|
26
|
+
ImportedPrivateMessage,
|
|
27
|
+
ImportedReputation,
|
|
28
|
+
ImportedSubscription,
|
|
29
|
+
ImportedThread,
|
|
30
|
+
ImportedUser,
|
|
31
|
+
ImportedUserRelation,
|
|
32
|
+
ImportedWarning,
|
|
33
|
+
} from './types'
|
|
34
|
+
import { fromUnixSeconds, visibilityOf } from './types'
|
|
35
|
+
|
|
36
|
+
export function mapUser(row: MybbUser): ImportedUser {
|
|
37
|
+
return {
|
|
38
|
+
legacyId: row.uid,
|
|
39
|
+
username: row.username,
|
|
40
|
+
email: row.email.trim().toLowerCase(),
|
|
41
|
+
legacyPasswordHash: `mybb$${row.salt}$${row.password}`,
|
|
42
|
+
registeredAt: fromUnixSeconds(row.regdate) ?? new Date(0),
|
|
43
|
+
lastVisitAt: fromUnixSeconds(row.lastvisit),
|
|
44
|
+
postCount: Math.max(0, row.postnum),
|
|
45
|
+
legacyGroupId: row.usergroup,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const FORUM_TYPES: Readonly<Record<string, ImportedForum['type']>> = {
|
|
50
|
+
f: 'forum',
|
|
51
|
+
c: 'category',
|
|
52
|
+
l: 'link',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function mapForum(row: MybbForum): ImportedForum {
|
|
56
|
+
return {
|
|
57
|
+
legacyId: row.fid,
|
|
58
|
+
type: FORUM_TYPES[row.type] ?? 'forum',
|
|
59
|
+
title: row.name,
|
|
60
|
+
description: row.description.trim() === '' ? null : row.description,
|
|
61
|
+
legacyParentId: row.pid === 0 ? null : row.pid,
|
|
62
|
+
displayOrder: row.disporder,
|
|
63
|
+
linkUrl: row.type === 'l' && row.linkto.trim() !== '' ? row.linkto : null,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function mapThread(row: MybbThread): ImportedThread {
|
|
68
|
+
const createdAt = fromUnixSeconds(row.dateline) ?? new Date(0)
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
legacyId: row.tid,
|
|
72
|
+
legacyForumId: row.fid,
|
|
73
|
+
title: row.subject,
|
|
74
|
+
legacyAuthorId: row.uid,
|
|
75
|
+
authorUsername: row.username,
|
|
76
|
+
createdAt,
|
|
77
|
+
lastPostAt: fromUnixSeconds(row.lastpost) ?? createdAt,
|
|
78
|
+
replyCount: Math.max(0, row.replies),
|
|
79
|
+
viewCount: Math.max(0, row.views),
|
|
80
|
+
isSticky: row.sticky === 1,
|
|
81
|
+
isLocked: row.closed === '1',
|
|
82
|
+
visibility: visibilityOf(row.visible),
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function mapPost(row: MybbPost): ImportedPost {
|
|
87
|
+
return {
|
|
88
|
+
legacyId: row.pid,
|
|
89
|
+
legacyThreadId: row.tid,
|
|
90
|
+
legacyForumId: row.fid,
|
|
91
|
+
legacyAuthorId: row.uid,
|
|
92
|
+
authorUsername: row.username,
|
|
93
|
+
body: row.message,
|
|
94
|
+
createdAt: fromUnixSeconds(row.dateline) ?? new Date(0),
|
|
95
|
+
editedAt: row.edituid === 0 ? null : fromUnixSeconds(row.edittime),
|
|
96
|
+
visibility: visibilityOf(row.visible),
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const AVATAR_SOURCES: Readonly<Record<string, ImportedAvatar['source']>> = {
|
|
101
|
+
upload: 'upload',
|
|
102
|
+
gallery: 'gallery',
|
|
103
|
+
remote: 'remote',
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function mapAvatar(row: MybbAvatarRow): ImportedAvatar | null {
|
|
107
|
+
const source = AVATAR_SOURCES[row.avatartype]
|
|
108
|
+
if (source === undefined) return null
|
|
109
|
+
|
|
110
|
+
const path = row.avatar.split('?')[0]?.replace(/^\.\//, '') ?? ''
|
|
111
|
+
if (path === '') return null
|
|
112
|
+
|
|
113
|
+
const [width, height] = row.avatardimensions.split('|').map((part) => Number(part))
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
legacyUserId: row.uid,
|
|
117
|
+
source,
|
|
118
|
+
path,
|
|
119
|
+
width: Number.isFinite(width) && width! > 0 ? width! : null,
|
|
120
|
+
height: Number.isFinite(height) && height! > 0 ? height! : null,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function mapAttachment(row: MybbAttachment): ImportedAttachment {
|
|
125
|
+
const path = row.attachname.replace(/^\.\//, '')
|
|
126
|
+
const thumbnail = row.thumbnail.trim()
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
legacyId: row.aid,
|
|
130
|
+
legacyPostId: row.pid,
|
|
131
|
+
legacyUserId: row.uid,
|
|
132
|
+
filename: row.filename,
|
|
133
|
+
contentType: row.filetype.trim() === '' ? null : row.filetype.trim(),
|
|
134
|
+
sizeBytes: Math.max(0, row.filesize),
|
|
135
|
+
path,
|
|
136
|
+
thumbnailPath:
|
|
137
|
+
thumbnail === '' || thumbnail === 'SMALL' ? null : thumbnail.replace(/^\.\//, ''),
|
|
138
|
+
downloadCount: Math.max(0, row.downloads),
|
|
139
|
+
createdAt: fromUnixSeconds(row.dateuploaded) ?? new Date(0),
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const OPTION_SEPARATOR = '||~|~||'
|
|
144
|
+
|
|
145
|
+
export function mapPoll(row: MybbPoll): ImportedPoll | null {
|
|
146
|
+
const labels = row.options.split(OPTION_SEPARATOR)
|
|
147
|
+
const counts = row.votes.split(OPTION_SEPARATOR)
|
|
148
|
+
const createdAt = fromUnixSeconds(row.dateline) ?? new Date(0)
|
|
149
|
+
|
|
150
|
+
const options = labels
|
|
151
|
+
.map((label, index) => ({
|
|
152
|
+
order: index + 1,
|
|
153
|
+
label: label.trim(),
|
|
154
|
+
voteCount: Math.max(0, Number(counts[index]) || 0),
|
|
155
|
+
}))
|
|
156
|
+
.filter((option) => option.label !== '')
|
|
157
|
+
|
|
158
|
+
if (options.length === 0) return null
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
legacyId: row.pid,
|
|
162
|
+
legacyThreadId: row.tid,
|
|
163
|
+
question: row.question,
|
|
164
|
+
options,
|
|
165
|
+
closesAt:
|
|
166
|
+
row.timeout > 0 ? new Date(createdAt.getTime() + row.timeout * 24 * 60 * 60 * 1000) : null,
|
|
167
|
+
createdAt,
|
|
168
|
+
maxOptions: row.multiple > 0 ? 0 : 1,
|
|
169
|
+
allowRevote: false,
|
|
170
|
+
publicVotes: row.public > 0,
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function mapPollVote(row: MybbPollVote): ImportedPollVote | null {
|
|
175
|
+
if (row.voteoption <= 0) return null
|
|
176
|
+
return {
|
|
177
|
+
legacyPollId: row.pid,
|
|
178
|
+
legacyUserId: row.uid,
|
|
179
|
+
optionOrder: row.voteoption,
|
|
180
|
+
votedAt: fromUnixSeconds(row.dateline),
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const PM_FOLDERS: Readonly<Record<number, 'inbox' | 'sent' | 'trash'>> = {
|
|
185
|
+
1: 'inbox',
|
|
186
|
+
2: 'sent',
|
|
187
|
+
4: 'trash',
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function mapPrivateMessage(row: MybbPrivateMessage): ImportedPrivateMessage | null {
|
|
191
|
+
if (row.folder === 3) return null
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
legacyId: row.pmid,
|
|
195
|
+
legacyAuthorId: row.fromid,
|
|
196
|
+
subject: row.subject,
|
|
197
|
+
body: row.message,
|
|
198
|
+
sentAt: fromUnixSeconds(row.dateline) ?? new Date(0),
|
|
199
|
+
copies: [
|
|
200
|
+
{
|
|
201
|
+
legacyOwnerId: row.uid,
|
|
202
|
+
folder: PM_FOLDERS[row.folder] ?? 'inbox',
|
|
203
|
+
readAt: row.status === 0 ? null : fromUnixSeconds(row.readtime),
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function mapThreadSubscription(row: MybbThreadSubscription): ImportedSubscription {
|
|
210
|
+
return {
|
|
211
|
+
legacyId: row.sid,
|
|
212
|
+
legacyUserId: row.uid,
|
|
213
|
+
legacyTargetId: row.tid,
|
|
214
|
+
mode: row.notification === 0 ? 'none' : 'instant',
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function mapForumSubscription(row: MybbForumSubscription): ImportedSubscription {
|
|
219
|
+
return {
|
|
220
|
+
legacyId: row.uid,
|
|
221
|
+
legacyUserId: row.uid,
|
|
222
|
+
legacyTargetId: row.fid,
|
|
223
|
+
mode: 'instant',
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function mapReputation(row: MybbReputation): ImportedReputation {
|
|
228
|
+
return {
|
|
229
|
+
legacyId: row.rid,
|
|
230
|
+
legacyUserId: row.uid,
|
|
231
|
+
legacyGivenByUserId: row.adduid,
|
|
232
|
+
legacyPostId: row.pid === 0 ? null : row.pid,
|
|
233
|
+
points: row.reputation,
|
|
234
|
+
comment: row.comments,
|
|
235
|
+
createdAt: fromUnixSeconds(row.dateline) ?? new Date(0),
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function mapWarning(row: MybbWarning): ImportedWarning {
|
|
240
|
+
return {
|
|
241
|
+
legacyId: row.wid,
|
|
242
|
+
legacyUserId: row.uid,
|
|
243
|
+
legacyIssuedByUserId: row.issuedby,
|
|
244
|
+
legacyPostId: row.pid === 0 ? null : row.pid,
|
|
245
|
+
title: row.title,
|
|
246
|
+
points: Math.max(0, row.points),
|
|
247
|
+
notes: row.notes,
|
|
248
|
+
issuedAt: fromUnixSeconds(row.dateline) ?? new Date(0),
|
|
249
|
+
expiresAt: fromUnixSeconds(row.expires),
|
|
250
|
+
revokedAt: fromUnixSeconds(row.daterevoked),
|
|
251
|
+
revokeReason: row.revokereason.trim() === '' ? null : row.revokereason,
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function mapBan(row: MybbBan): ImportedBan {
|
|
256
|
+
return {
|
|
257
|
+
legacyId: row.uid,
|
|
258
|
+
legacyUserId: row.uid,
|
|
259
|
+
legacyBannedByUserId: row.admin,
|
|
260
|
+
reason: row.reason,
|
|
261
|
+
publicReason: null,
|
|
262
|
+
createdAt: fromUnixSeconds(row.dateline) ?? new Date(0),
|
|
263
|
+
expiresAt: fromUnixSeconds(row.lifted),
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function idList(list: string): number[] {
|
|
268
|
+
return [
|
|
269
|
+
...new Set(
|
|
270
|
+
list
|
|
271
|
+
.split(',')
|
|
272
|
+
.map((part) => Number(part.trim()))
|
|
273
|
+
.filter((id) => Number.isSafeInteger(id) && id > 0),
|
|
274
|
+
),
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export function mapRelationList(row: MybbRelationList): ImportedUserRelation[] {
|
|
279
|
+
const buddies = idList(row.buddylist)
|
|
280
|
+
const ignoredSet = new Set(idList(row.ignorelist))
|
|
281
|
+
const buddySet = new Set(buddies)
|
|
282
|
+
|
|
283
|
+
return [
|
|
284
|
+
...buddies.map((other) => ({
|
|
285
|
+
legacyUserId: row.uid,
|
|
286
|
+
legacyOtherUserId: other,
|
|
287
|
+
kind: 'buddy' as const,
|
|
288
|
+
})),
|
|
289
|
+
...[...ignoredSet]
|
|
290
|
+
.filter((other) => !buddySet.has(other))
|
|
291
|
+
.map((other) => ({
|
|
292
|
+
legacyUserId: row.uid,
|
|
293
|
+
legacyOtherUserId: other,
|
|
294
|
+
kind: 'ignore' as const,
|
|
295
|
+
})),
|
|
296
|
+
].filter((relation) => relation.legacyOtherUserId !== row.uid)
|
|
297
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ImportSink, WriteResult } from './run'
|
|
2
|
+
|
|
3
|
+
const byLegacyId = (row: { legacyId: number }): string => String(row.legacyId)
|
|
4
|
+
const byPair = (row: { legacyUserId: number; legacyTargetId: number }): string =>
|
|
5
|
+
`${row.legacyUserId}:${row.legacyTargetId}`
|
|
6
|
+
|
|
7
|
+
export class MemorySink implements ImportSink {
|
|
8
|
+
readonly stored = new Map<string, Map<string, unknown>>()
|
|
9
|
+
readonly calls: string[] = []
|
|
10
|
+
|
|
11
|
+
putUsers = (rows: readonly { legacyId: number }[]) => this.#put('users', rows, byLegacyId)
|
|
12
|
+
putForums = (rows: readonly { legacyId: number }[]) => this.#put('forums', rows, byLegacyId)
|
|
13
|
+
putThreads = (rows: readonly { legacyId: number }[]) => this.#put('threads', rows, byLegacyId)
|
|
14
|
+
putPosts = (rows: readonly { legacyId: number }[]) => this.#put('posts', rows, byLegacyId)
|
|
15
|
+
putAvatars = (rows: readonly { legacyUserId: number }[]) =>
|
|
16
|
+
this.#put('avatars', rows, (row) => String(row.legacyUserId))
|
|
17
|
+
putAttachments = (rows: readonly { legacyId: number }[]) =>
|
|
18
|
+
this.#put('attachments', rows, byLegacyId)
|
|
19
|
+
putPolls = (rows: readonly { legacyId: number }[]) => this.#put('polls', rows, byLegacyId)
|
|
20
|
+
putPollVotes = (
|
|
21
|
+
rows: readonly { legacyPollId: number; legacyUserId: number; optionOrder: number }[],
|
|
22
|
+
) =>
|
|
23
|
+
this.#put(
|
|
24
|
+
'pollVotes',
|
|
25
|
+
rows,
|
|
26
|
+
(row) => `${row.legacyPollId}:${row.legacyUserId}:${row.optionOrder}`,
|
|
27
|
+
)
|
|
28
|
+
putPrivateMessages = (rows: readonly { legacyId: number }[]) =>
|
|
29
|
+
this.#put('privateMessages', rows, byLegacyId)
|
|
30
|
+
putThreadSubscriptions = (rows: readonly { legacyUserId: number; legacyTargetId: number }[]) =>
|
|
31
|
+
this.#put('threadSubscriptions', rows, byPair)
|
|
32
|
+
putForumSubscriptions = (rows: readonly { legacyUserId: number; legacyTargetId: number }[]) =>
|
|
33
|
+
this.#put('forumSubscriptions', rows, byPair)
|
|
34
|
+
putReputation = (rows: readonly { legacyId: number }[]) =>
|
|
35
|
+
this.#put('reputation', rows, byLegacyId)
|
|
36
|
+
putWarnings = (rows: readonly { legacyId: number }[]) => this.#put('warnings', rows, byLegacyId)
|
|
37
|
+
putBans = (rows: readonly { legacyId: number }[]) => this.#put('bans', rows, byLegacyId)
|
|
38
|
+
putUserRelations = (rows: readonly { legacyUserId: number; legacyOtherUserId: number }[]) =>
|
|
39
|
+
this.#put('userRelations', rows, (row) => `${row.legacyUserId}:${row.legacyOtherUserId}`)
|
|
40
|
+
|
|
41
|
+
count(kind: string): number {
|
|
42
|
+
return this.stored.get(kind)?.size ?? 0
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
rows<T>(kind: string): readonly T[] {
|
|
46
|
+
return [...(this.stored.get(kind)?.values() ?? [])] as T[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async #put<T>(kind: string, rows: readonly T[], keyOf: (row: T) => string): Promise<WriteResult> {
|
|
50
|
+
this.calls.push(`${kind}:${rows.length}`)
|
|
51
|
+
const table = this.stored.get(kind) ?? new Map<string, unknown>()
|
|
52
|
+
this.stored.set(kind, table)
|
|
53
|
+
|
|
54
|
+
let inserted = 0
|
|
55
|
+
let updated = 0
|
|
56
|
+
for (const row of rows) {
|
|
57
|
+
const key = keyOf(row)
|
|
58
|
+
if (table.has(key)) updated += 1
|
|
59
|
+
else inserted += 1
|
|
60
|
+
table.set(key, row)
|
|
61
|
+
}
|
|
62
|
+
return { inserted, updated, skipped: [] }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mapAttachment,
|
|
3
|
+
mapAvatar,
|
|
4
|
+
mapBan,
|
|
5
|
+
mapForum,
|
|
6
|
+
mapForumSubscription,
|
|
7
|
+
mapPoll,
|
|
8
|
+
mapPollVote,
|
|
9
|
+
mapPost,
|
|
10
|
+
mapPrivateMessage,
|
|
11
|
+
mapRelationList,
|
|
12
|
+
mapReputation,
|
|
13
|
+
mapThread,
|
|
14
|
+
mapThreadSubscription,
|
|
15
|
+
mapUser,
|
|
16
|
+
mapWarning,
|
|
17
|
+
} from './map'
|
|
18
|
+
import type { MybbTables } from './mybb-rows'
|
|
19
|
+
import { groupRows, type ImportSource, type Page, pageByGroup, pageById } from './source'
|
|
20
|
+
import type {
|
|
21
|
+
ImportedAttachment,
|
|
22
|
+
ImportedAvatar,
|
|
23
|
+
ImportedBan,
|
|
24
|
+
ImportedForum,
|
|
25
|
+
ImportedPoll,
|
|
26
|
+
ImportedPollVote,
|
|
27
|
+
ImportedPost,
|
|
28
|
+
ImportedPrivateMessage,
|
|
29
|
+
ImportedReputation,
|
|
30
|
+
ImportedSubscription,
|
|
31
|
+
ImportedThread,
|
|
32
|
+
ImportedUser,
|
|
33
|
+
ImportedUserRelation,
|
|
34
|
+
ImportedWarning,
|
|
35
|
+
} from './types'
|
|
36
|
+
|
|
37
|
+
function mapPage<Raw, Mapped>(page: Page<Raw>, map: (row: Raw) => Mapped | null): Page<Mapped> {
|
|
38
|
+
return {
|
|
39
|
+
rows: page.rows.map(map).filter((row): row is NonNullable<Mapped> => row !== null),
|
|
40
|
+
nextCursor: page.nextCursor,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class FixtureMybbSource implements ImportSource {
|
|
45
|
+
readonly name = 'mybb'
|
|
46
|
+
|
|
47
|
+
constructor(private readonly data: MybbTables) {}
|
|
48
|
+
|
|
49
|
+
users(afterId: number, limit: number): Promise<Page<ImportedUser>> {
|
|
50
|
+
return Promise.resolve(
|
|
51
|
+
mapPage(
|
|
52
|
+
pageById(this.data.users ?? [], (row) => row.uid, afterId, limit),
|
|
53
|
+
mapUser,
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
forums(afterId: number, limit: number): Promise<Page<ImportedForum>> {
|
|
59
|
+
return Promise.resolve(
|
|
60
|
+
mapPage(
|
|
61
|
+
pageById(this.data.forums ?? [], (row) => row.fid, afterId, limit),
|
|
62
|
+
mapForum,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
threads(afterId: number, limit: number): Promise<Page<ImportedThread>> {
|
|
68
|
+
return Promise.resolve(
|
|
69
|
+
mapPage(
|
|
70
|
+
pageById(this.data.threads ?? [], (row) => row.tid, afterId, limit),
|
|
71
|
+
mapThread,
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
posts(afterId: number, limit: number): Promise<Page<ImportedPost>> {
|
|
77
|
+
return Promise.resolve(
|
|
78
|
+
mapPage(
|
|
79
|
+
pageById(this.data.posts ?? [], (row) => row.pid, afterId, limit),
|
|
80
|
+
mapPost,
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
avatars(afterId: number, limit: number): Promise<Page<ImportedAvatar>> {
|
|
86
|
+
return Promise.resolve(
|
|
87
|
+
mapPage(
|
|
88
|
+
pageById(this.data.avatars ?? [], (row) => row.uid, afterId, limit),
|
|
89
|
+
mapAvatar,
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
attachments(afterId: number, limit: number): Promise<Page<ImportedAttachment>> {
|
|
95
|
+
return Promise.resolve(
|
|
96
|
+
mapPage(
|
|
97
|
+
pageById(this.data.attachments ?? [], (row) => row.aid, afterId, limit),
|
|
98
|
+
mapAttachment,
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
polls(afterId: number, limit: number): Promise<Page<ImportedPoll>> {
|
|
104
|
+
return Promise.resolve(
|
|
105
|
+
mapPage(
|
|
106
|
+
pageById(this.data.polls ?? [], (row) => row.pid, afterId, limit),
|
|
107
|
+
mapPoll,
|
|
108
|
+
),
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pollVotes(afterId: number, limit: number): Promise<Page<ImportedPollVote>> {
|
|
113
|
+
return Promise.resolve(
|
|
114
|
+
mapPage(
|
|
115
|
+
pageById(this.data.pollVotes ?? [], (row) => row.vid, afterId, limit),
|
|
116
|
+
mapPollVote,
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
privateMessages(afterId: number, limit: number): Promise<Page<ImportedPrivateMessage>> {
|
|
122
|
+
return Promise.resolve(
|
|
123
|
+
mapPage(
|
|
124
|
+
pageById(this.data.privateMessages ?? [], (row) => row.pmid, afterId, limit),
|
|
125
|
+
mapPrivateMessage,
|
|
126
|
+
),
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
threadSubscriptions(afterId: number, limit: number): Promise<Page<ImportedSubscription>> {
|
|
131
|
+
return Promise.resolve(
|
|
132
|
+
mapPage(
|
|
133
|
+
pageById(this.data.threadSubscriptions ?? [], (row) => row.sid, afterId, limit),
|
|
134
|
+
mapThreadSubscription,
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async forumSubscriptions(afterId: number, limit: number): Promise<Page<ImportedSubscription>> {
|
|
140
|
+
const { fetch, fetchGroup } = groupRows(this.data.forumSubscriptions ?? [], (row) => row.uid)
|
|
141
|
+
const page = await pageByGroup({
|
|
142
|
+
afterGroup: afterId,
|
|
143
|
+
limit,
|
|
144
|
+
groupOf: (row) => row.uid,
|
|
145
|
+
fetch,
|
|
146
|
+
fetchGroup,
|
|
147
|
+
})
|
|
148
|
+
return mapPage(page, mapForumSubscription)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
reputation(afterId: number, limit: number): Promise<Page<ImportedReputation>> {
|
|
152
|
+
return Promise.resolve(
|
|
153
|
+
mapPage(
|
|
154
|
+
pageById(this.data.reputation ?? [], (row) => row.rid, afterId, limit),
|
|
155
|
+
mapReputation,
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
warnings(afterId: number, limit: number): Promise<Page<ImportedWarning>> {
|
|
161
|
+
return Promise.resolve(
|
|
162
|
+
mapPage(
|
|
163
|
+
pageById(this.data.warnings ?? [], (row) => row.wid, afterId, limit),
|
|
164
|
+
mapWarning,
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
bans(afterId: number, limit: number): Promise<Page<ImportedBan>> {
|
|
170
|
+
return Promise.resolve(
|
|
171
|
+
mapPage(
|
|
172
|
+
pageById(this.data.bans ?? [], (row) => row.uid, afterId, limit),
|
|
173
|
+
mapBan,
|
|
174
|
+
),
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
userRelations(afterId: number, limit: number): Promise<Page<ImportedUserRelation>> {
|
|
179
|
+
const page = pageById(this.data.relationLists ?? [], (row) => row.uid, afterId, limit)
|
|
180
|
+
return Promise.resolve({
|
|
181
|
+
rows: page.rows.flatMap(mapRelationList),
|
|
182
|
+
nextCursor: page.nextCursor,
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
}
|
package/src/mybb-rows.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
export interface MybbUser {
|
|
2
|
+
readonly uid: number
|
|
3
|
+
readonly username: string
|
|
4
|
+
readonly email: string
|
|
5
|
+
readonly password: string
|
|
6
|
+
readonly salt: string
|
|
7
|
+
readonly usergroup: number
|
|
8
|
+
readonly regdate: number
|
|
9
|
+
readonly lastvisit: number
|
|
10
|
+
readonly postnum: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface MybbForum {
|
|
14
|
+
readonly fid: number
|
|
15
|
+
readonly name: string
|
|
16
|
+
readonly description: string
|
|
17
|
+
readonly type: string
|
|
18
|
+
readonly pid: number
|
|
19
|
+
readonly disporder: number
|
|
20
|
+
readonly linkto: string
|
|
21
|
+
readonly threads: number
|
|
22
|
+
readonly posts: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface MybbThread {
|
|
26
|
+
readonly tid: number
|
|
27
|
+
readonly fid: number
|
|
28
|
+
readonly subject: string
|
|
29
|
+
readonly uid: number
|
|
30
|
+
readonly username: string
|
|
31
|
+
readonly dateline: number
|
|
32
|
+
readonly lastpost: number
|
|
33
|
+
readonly replies: number
|
|
34
|
+
readonly views: number
|
|
35
|
+
readonly sticky: number
|
|
36
|
+
readonly closed: string
|
|
37
|
+
readonly visible: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface MybbPost {
|
|
41
|
+
readonly pid: number
|
|
42
|
+
readonly tid: number
|
|
43
|
+
readonly fid: number
|
|
44
|
+
readonly uid: number
|
|
45
|
+
readonly username: string
|
|
46
|
+
readonly subject: string
|
|
47
|
+
readonly message: string
|
|
48
|
+
readonly dateline: number
|
|
49
|
+
readonly edituid: number
|
|
50
|
+
readonly edittime: number
|
|
51
|
+
readonly visible: number
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface MybbAvatarRow {
|
|
55
|
+
readonly uid: number
|
|
56
|
+
readonly avatar: string
|
|
57
|
+
readonly avatartype: string
|
|
58
|
+
readonly avatardimensions: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface MybbAttachment {
|
|
62
|
+
readonly aid: number
|
|
63
|
+
readonly pid: number
|
|
64
|
+
readonly uid: number
|
|
65
|
+
readonly filename: string
|
|
66
|
+
readonly filetype: string
|
|
67
|
+
readonly filesize: number
|
|
68
|
+
readonly attachname: string
|
|
69
|
+
readonly thumbnail: string
|
|
70
|
+
readonly downloads: number
|
|
71
|
+
readonly dateuploaded: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface MybbPoll {
|
|
75
|
+
readonly pid: number
|
|
76
|
+
readonly tid: number
|
|
77
|
+
readonly question: string
|
|
78
|
+
readonly dateline: number
|
|
79
|
+
readonly options: string
|
|
80
|
+
readonly votes: string
|
|
81
|
+
readonly timeout: number
|
|
82
|
+
readonly multiple: number
|
|
83
|
+
readonly public: number
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface MybbPollVote {
|
|
87
|
+
readonly vid: number
|
|
88
|
+
readonly pid: number
|
|
89
|
+
readonly uid: number
|
|
90
|
+
readonly voteoption: number
|
|
91
|
+
readonly dateline: number
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface MybbPrivateMessage {
|
|
95
|
+
readonly pmid: number
|
|
96
|
+
readonly uid: number
|
|
97
|
+
readonly fromid: number
|
|
98
|
+
readonly subject: string
|
|
99
|
+
readonly message: string
|
|
100
|
+
readonly dateline: number
|
|
101
|
+
readonly folder: number
|
|
102
|
+
readonly status: number
|
|
103
|
+
readonly readtime: number
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface MybbThreadSubscription {
|
|
107
|
+
readonly sid: number
|
|
108
|
+
readonly uid: number
|
|
109
|
+
readonly tid: number
|
|
110
|
+
readonly notification: number
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface MybbForumSubscription {
|
|
114
|
+
readonly fid: number
|
|
115
|
+
readonly uid: number
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface MybbReputation {
|
|
119
|
+
readonly rid: number
|
|
120
|
+
readonly uid: number
|
|
121
|
+
readonly adduid: number
|
|
122
|
+
readonly pid: number
|
|
123
|
+
readonly reputation: number
|
|
124
|
+
readonly dateline: number
|
|
125
|
+
readonly comments: string
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface MybbWarning {
|
|
129
|
+
readonly wid: number
|
|
130
|
+
readonly uid: number
|
|
131
|
+
readonly pid: number
|
|
132
|
+
readonly title: string
|
|
133
|
+
readonly points: number
|
|
134
|
+
readonly dateline: number
|
|
135
|
+
readonly issuedby: number
|
|
136
|
+
readonly expires: number
|
|
137
|
+
readonly daterevoked: number
|
|
138
|
+
readonly revokereason: string
|
|
139
|
+
readonly notes: string
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface MybbBan {
|
|
143
|
+
readonly uid: number
|
|
144
|
+
readonly admin: number
|
|
145
|
+
readonly dateline: number
|
|
146
|
+
readonly lifted: number
|
|
147
|
+
readonly reason: string
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface MybbRelationList {
|
|
151
|
+
readonly uid: number
|
|
152
|
+
readonly buddylist: string
|
|
153
|
+
readonly ignorelist: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface MybbTables {
|
|
157
|
+
readonly users?: readonly MybbUser[]
|
|
158
|
+
readonly forums?: readonly MybbForum[]
|
|
159
|
+
readonly threads?: readonly MybbThread[]
|
|
160
|
+
readonly posts?: readonly MybbPost[]
|
|
161
|
+
readonly avatars?: readonly MybbAvatarRow[]
|
|
162
|
+
readonly attachments?: readonly MybbAttachment[]
|
|
163
|
+
readonly polls?: readonly MybbPoll[]
|
|
164
|
+
readonly pollVotes?: readonly MybbPollVote[]
|
|
165
|
+
readonly privateMessages?: readonly MybbPrivateMessage[]
|
|
166
|
+
readonly threadSubscriptions?: readonly MybbThreadSubscription[]
|
|
167
|
+
readonly forumSubscriptions?: readonly MybbForumSubscription[]
|
|
168
|
+
readonly reputation?: readonly MybbReputation[]
|
|
169
|
+
readonly warnings?: readonly MybbWarning[]
|
|
170
|
+
readonly bans?: readonly MybbBan[]
|
|
171
|
+
readonly relationLists?: readonly MybbRelationList[]
|
|
172
|
+
}
|