blob: 06613d51094f12478806a2af788b1713a1598330 [file] [log] [blame]
Adrià Vilanova Martínez7c1a3c12024-12-05 15:34:40 +01001import { CCApi } from '../../common/api.js';
2import { getAuthUser } from '../../common/communityConsoleUtils.js';
3import { ProtobufNumber } from '../../common/protojs.types.js';
4import GapModel from '../../models/Gap.js';
5import MessageModel from '../../models/Message';
6import ThreadModel from '../../models/Thread';
7import { Modifier } from './types.js';
8
9const authuser = getAuthUser();
10
11const loadMoreThread: Modifier = {
12 urlRegex: /api\/ViewThread/i,
13 featureGated: true,
14 features: ['flattenthreads', 'flattenthreads_switch_enabled'],
15 isEnabled(options) {
16 return (
17 options['flattenthreads'] && options['flattenthreads_switch_enabled']
18 );
19 },
20 async interceptor(response, url) {
21 if (!response[1]?.[40]) return response;
22
23 const thread = new ThreadModel(response[1]);
24
25 if (!thread.getForumId() || !thread.getId()) {
26 console.error(
27 "[loadMoreThread] Couldn't find forum id and thread id for:",
28 url,
29 );
30 return response;
31 }
32
33 const mogs = thread.getMessageOrGapModels();
34 thread.setRawCommentsAndGaps(
35 await loadGaps(thread.getForumId(), thread.getId(), mogs, 0),
36 );
37
38 response[1] = thread.toRawThread();
39 return response;
40 },
41};
42
43function loadGaps(
44 forumId: ProtobufNumber,
45 threadId: ProtobufNumber,
46 mogs: Array<MessageModel | GapModel>,
47 it: number,
48): Promise<Array<MessageModel | GapModel>> {
49 if (it >= 10) {
50 return Promise.reject(
51 new Error(
52 'loadGaps has been called for more than 10 times, ' +
53 "which means we've entered an infinite loop.",
54 ),
55 );
56 }
57
58 const messageOrGapPromises = [];
59 messageOrGapPromises.push(
60 Promise.resolve(mogs.filter((mog) => mog !== undefined)),
61 );
62 mogs.forEach((mog) => {
63 if (mog instanceof GapModel) {
64 messageOrGapPromises.push(loadGap(forumId, threadId, mog));
65 }
66 if (mog instanceof MessageModel) {
67 mog.getCommentsAndGaps().forEach((cog) => {
68 if (cog instanceof GapModel) {
69 messageOrGapPromises.push(loadGap(forumId, threadId, cog));
70 }
71 });
72 }
73 });
74
75 return Promise.all(messageOrGapPromises).then((res) => {
76 // #!if !production
77 console.time('mergeMessages');
78 // #!endif
79 const mogs = ThreadModel.mergeMessageOrGapsMultiarray(res);
80 // #!if !production
81 console.timeEnd('mergeMessages');
82 // #!endif
83
84 if (
85 mogs.some((mog) => {
86 return (
87 mog instanceof GapModel ||
88 mog.getCommentsAndGaps().some((cog) => cog instanceof GapModel)
89 );
90 })
91 ) {
92 return loadGaps(forumId, threadId, mogs, it + 1);
93 }
94 return mogs.map((message) => message.toRawMessageOrGap());
95 });
96}
97
98async function loadGap(
99 forumId: ProtobufNumber,
100 threadId: ProtobufNumber,
101 gap: GapModel,
102): Promise<Array<MessageModel | GapModel>> {
103 return CCApi(
104 'ViewThread',
105 {
106 1: forumId,
107 2: threadId,
108 3: {
109 // options
110 1: {
111 // pagination
112 2: gap.getCount(), // maxNum
113 7: {
114 // targetRange
115 1: gap.getStartMicroseconds(), // startMicroseconds
116 2: gap.getEndMicroseconds(), // endMicroseconds
117 3: gap.getParentId(), // parentId
118 },
119 },
120 5: true, // withUserProfile
121 10: true, // withPromotedMessages
122 },
123 },
124 /* authenticated = */ true,
125 authuser,
126 ).then((res) => {
127 const thread = new ThreadModel(res[1]);
128 return thread.getMessageOrGapModels();
129 });
130}
131
132export default loadMoreThread;