]> Untitled Git - lemmy.git/blob - api_tests/src/shared.ts
Delete migrations_testing folder (#3751)
[lemmy.git] / api_tests / src / shared.ts
1 import { LemmyHttp } from "lemmy-js-client";
2 import { CreatePost } from "lemmy-js-client/dist/types/CreatePost";
3 import { DeletePost } from "lemmy-js-client/dist/types/DeletePost";
4 import { EditPost } from "lemmy-js-client/dist/types/EditPost";
5 import { EditSite } from "lemmy-js-client/dist/types/EditSite";
6 import { FeaturePost } from "lemmy-js-client/dist/types/FeaturePost";
7 import { GetComments } from "lemmy-js-client/dist/types/GetComments";
8 import { GetCommentsResponse } from "lemmy-js-client/dist/types/GetCommentsResponse";
9 import { GetPost } from "lemmy-js-client/dist/types/GetPost";
10 import { GetPostResponse } from "lemmy-js-client/dist/types/GetPostResponse";
11 import { LockPost } from "lemmy-js-client/dist/types/LockPost";
12 import { Login } from "lemmy-js-client/dist/types/Login";
13 import { Post } from "lemmy-js-client/dist/types/Post";
14 import { PostResponse } from "lemmy-js-client/dist/types/PostResponse";
15 import { RemovePost } from "lemmy-js-client/dist/types/RemovePost";
16 import { ResolveObject } from "lemmy-js-client/dist/types/ResolveObject";
17 import { ResolveObjectResponse } from "lemmy-js-client/dist/types/ResolveObjectResponse";
18 import { Search } from "lemmy-js-client/dist/types/Search";
19 import { SearchResponse } from "lemmy-js-client/dist/types/SearchResponse";
20 import { Comment } from "lemmy-js-client/dist/types/Comment";
21 import { BanPersonResponse } from "lemmy-js-client/dist/types/BanPersonResponse";
22 import { BanPerson } from "lemmy-js-client/dist/types/BanPerson";
23 import { BanFromCommunityResponse } from "lemmy-js-client/dist/types/BanFromCommunityResponse";
24 import { BanFromCommunity } from "lemmy-js-client/dist/types/BanFromCommunity";
25 import { CommunityResponse } from "lemmy-js-client/dist/types/CommunityResponse";
26 import { FollowCommunity } from "lemmy-js-client/dist/types/FollowCommunity";
27 import { CreatePostLike } from "lemmy-js-client/dist/types/CreatePostLike";
28 import { CommentResponse } from "lemmy-js-client/dist/types/CommentResponse";
29 import { CreateComment } from "lemmy-js-client/dist/types/CreateComment";
30 import { EditComment } from "lemmy-js-client/dist/types/EditComment";
31 import { DeleteComment } from "lemmy-js-client/dist/types/DeleteComment";
32 import { RemoveComment } from "lemmy-js-client/dist/types/RemoveComment";
33 import { GetPersonMentionsResponse } from "lemmy-js-client/dist/types/GetPersonMentionsResponse";
34 import { GetPersonMentions } from "lemmy-js-client/dist/types/GetPersonMentions";
35 import { CreateCommentLike } from "lemmy-js-client/dist/types/CreateCommentLike";
36 import { CreateCommunity } from "lemmy-js-client/dist/types/CreateCommunity";
37 import { GetCommunity } from "lemmy-js-client/dist/types/GetCommunity";
38 import { DeleteCommunity } from "lemmy-js-client/dist/types/DeleteCommunity";
39 import { RemoveCommunity } from "lemmy-js-client/dist/types/RemoveCommunity";
40 import { PrivateMessageResponse } from "lemmy-js-client/dist/types/PrivateMessageResponse";
41 import { CreatePrivateMessage } from "lemmy-js-client/dist/types/CreatePrivateMessage";
42 import { EditPrivateMessage } from "lemmy-js-client/dist/types/EditPrivateMessage";
43 import { DeletePrivateMessage } from "lemmy-js-client/dist/types/DeletePrivateMessage";
44 import { LoginResponse } from "lemmy-js-client/dist/types/LoginResponse";
45 import { Register } from "lemmy-js-client/dist/types/Register";
46 import { SaveUserSettings } from "lemmy-js-client/dist/types/SaveUserSettings";
47 import { DeleteAccount } from "lemmy-js-client/dist/types/DeleteAccount";
48 import { GetSiteResponse } from "lemmy-js-client/dist/types/GetSiteResponse";
49 import { DeleteAccountResponse } from "lemmy-js-client/dist/types/DeleteAccountResponse";
50 import { GetSite } from "lemmy-js-client/dist/types/GetSite";
51 import { PrivateMessagesResponse } from "lemmy-js-client/dist/types/PrivateMessagesResponse";
52 import { GetPrivateMessages } from "lemmy-js-client/dist/types/GetPrivateMessages";
53 import { PostReportResponse } from "lemmy-js-client/dist/types/PostReportResponse";
54 import { CreatePostReport } from "lemmy-js-client/dist/types/CreatePostReport";
55 import { ListPostReportsResponse } from "lemmy-js-client/dist/types/ListPostReportsResponse";
56 import { ListPostReports } from "lemmy-js-client/dist/types/ListPostReports";
57 import { CommentReportResponse } from "lemmy-js-client/dist/types/CommentReportResponse";
58 import { CreateCommentReport } from "lemmy-js-client/dist/types/CreateCommentReport";
59 import { ListCommentReportsResponse } from "lemmy-js-client/dist/types/ListCommentReportsResponse";
60 import { ListCommentReports } from "lemmy-js-client/dist/types/ListCommentReports";
61 import { GetPostsResponse } from "lemmy-js-client/dist/types/GetPostsResponse";
62 import { GetPosts } from "lemmy-js-client/dist/types/GetPosts";
63 import { GetPersonDetailsResponse } from "lemmy-js-client/dist/types/GetPersonDetailsResponse";
64 import { GetPersonDetails } from "lemmy-js-client/dist/types/GetPersonDetails";
65
66 export interface API {
67   client: LemmyHttp;
68   auth: string;
69 }
70
71 export let alpha: API = {
72   client: new LemmyHttp("http://127.0.0.1:8541"),
73   auth: "",
74 };
75
76 export let beta: API = {
77   client: new LemmyHttp("http://127.0.0.1:8551"),
78   auth: "",
79 };
80
81 export let gamma: API = {
82   client: new LemmyHttp("http://127.0.0.1:8561"),
83   auth: "",
84 };
85
86 export let delta: API = {
87   client: new LemmyHttp("http://127.0.0.1:8571"),
88   auth: "",
89 };
90
91 export let epsilon: API = {
92   client: new LemmyHttp("http://127.0.0.1:8581"),
93   auth: "",
94 };
95
96 const password = "lemmylemmy";
97
98 export async function setupLogins() {
99   let formAlpha: Login = {
100     username_or_email: "lemmy_alpha",
101     password,
102   };
103   let resAlpha = alpha.client.login(formAlpha);
104
105   let formBeta: Login = {
106     username_or_email: "lemmy_beta",
107     password,
108   };
109   let resBeta = beta.client.login(formBeta);
110
111   let formGamma: Login = {
112     username_or_email: "lemmy_gamma",
113     password,
114   };
115   let resGamma = gamma.client.login(formGamma);
116
117   let formDelta: Login = {
118     username_or_email: "lemmy_delta",
119     password,
120   };
121   let resDelta = delta.client.login(formDelta);
122
123   let formEpsilon: Login = {
124     username_or_email: "lemmy_epsilon",
125     password,
126   };
127   let resEpsilon = epsilon.client.login(formEpsilon);
128
129   let res = await Promise.all([
130     resAlpha,
131     resBeta,
132     resGamma,
133     resDelta,
134     resEpsilon,
135   ]);
136
137   alpha.auth = res[0].jwt ?? "";
138   beta.auth = res[1].jwt ?? "";
139   gamma.auth = res[2].jwt ?? "";
140   delta.auth = res[3].jwt ?? "";
141   epsilon.auth = res[4].jwt ?? "";
142
143   // Registration applications are now enabled by default, need to disable them
144   let editSiteForm: EditSite = {
145     registration_mode: "Open",
146     rate_limit_message: 999,
147     rate_limit_post: 999,
148     rate_limit_register: 999,
149     rate_limit_image: 999,
150     rate_limit_comment: 999,
151     rate_limit_search: 999,
152     auth: "",
153   };
154
155   // Set the blocks and auths for each
156   editSiteForm.auth = alpha.auth;
157   editSiteForm.allowed_instances = [
158     "lemmy-beta",
159     "lemmy-gamma",
160     "lemmy-delta",
161     "lemmy-epsilon",
162   ];
163   await alpha.client.editSite(editSiteForm);
164
165   editSiteForm.auth = beta.auth;
166   editSiteForm.allowed_instances = [
167     "lemmy-alpha",
168     "lemmy-gamma",
169     "lemmy-delta",
170     "lemmy-epsilon",
171   ];
172   await beta.client.editSite(editSiteForm);
173
174   editSiteForm.auth = gamma.auth;
175   editSiteForm.allowed_instances = [
176     "lemmy-alpha",
177     "lemmy-beta",
178     "lemmy-delta",
179     "lemmy-epsilon",
180   ];
181   await gamma.client.editSite(editSiteForm);
182
183   editSiteForm.allowed_instances = ["lemmy-beta"];
184   editSiteForm.auth = delta.auth;
185   await delta.client.editSite(editSiteForm);
186
187   editSiteForm.auth = epsilon.auth;
188   editSiteForm.allowed_instances = [];
189   editSiteForm.blocked_instances = ["lemmy-alpha"];
190   await epsilon.client.editSite(editSiteForm);
191
192   // Create the main alpha/beta communities
193   // Ignore thrown errors of duplicates
194   try {
195     await createCommunity(alpha, "main");
196     await createCommunity(beta, "main");
197   } catch (_) {}
198 }
199
200 export async function createPost(
201   api: API,
202   community_id: number,
203 ): Promise<PostResponse> {
204   let name = randomString(5);
205   let body = randomString(10);
206   let url = "https://google.com/";
207   let form: CreatePost = {
208     name,
209     url,
210     body,
211     auth: api.auth,
212     community_id,
213   };
214   return api.client.createPost(form);
215 }
216
217 export async function editPost(api: API, post: Post): Promise<PostResponse> {
218   let name = "A jest test federated post, updated";
219   let form: EditPost = {
220     name,
221     post_id: post.id,
222     auth: api.auth,
223   };
224   return api.client.editPost(form);
225 }
226
227 export async function deletePost(
228   api: API,
229   deleted: boolean,
230   post: Post,
231 ): Promise<PostResponse> {
232   let form: DeletePost = {
233     post_id: post.id,
234     deleted: deleted,
235     auth: api.auth,
236   };
237   return api.client.deletePost(form);
238 }
239
240 export async function removePost(
241   api: API,
242   removed: boolean,
243   post: Post,
244 ): Promise<PostResponse> {
245   let form: RemovePost = {
246     post_id: post.id,
247     removed,
248     auth: api.auth,
249   };
250   return api.client.removePost(form);
251 }
252
253 export async function featurePost(
254   api: API,
255   featured: boolean,
256   post: Post,
257 ): Promise<PostResponse> {
258   let form: FeaturePost = {
259     post_id: post.id,
260     featured,
261     feature_type: "Community",
262     auth: api.auth,
263   };
264   return api.client.featurePost(form);
265 }
266
267 export async function lockPost(
268   api: API,
269   locked: boolean,
270   post: Post,
271 ): Promise<PostResponse> {
272   let form: LockPost = {
273     post_id: post.id,
274     locked,
275     auth: api.auth,
276   };
277   return api.client.lockPost(form);
278 }
279
280 export async function resolvePost(
281   api: API,
282   post: Post,
283 ): Promise<ResolveObjectResponse> {
284   let form: ResolveObject = {
285     q: post.ap_id,
286     auth: api.auth,
287   };
288   return api.client.resolveObject(form);
289 }
290
291 export async function searchPostLocal(
292   api: API,
293   post: Post,
294 ): Promise<SearchResponse> {
295   let form: Search = {
296     q: post.name,
297     type_: "Posts",
298     sort: "TopAll",
299     auth: api.auth,
300   };
301   return api.client.search(form);
302 }
303
304 export async function getPost(
305   api: API,
306   post_id: number,
307 ): Promise<GetPostResponse> {
308   let form: GetPost = {
309     id: post_id,
310     auth: api.auth,
311   };
312   return api.client.getPost(form);
313 }
314
315 export async function getComments(
316   api: API,
317   post_id: number,
318 ): Promise<GetCommentsResponse> {
319   let form: GetComments = {
320     post_id: post_id,
321     type_: "All",
322     sort: "New",
323     auth: api.auth,
324   };
325   return api.client.getComments(form);
326 }
327
328 export async function resolveComment(
329   api: API,
330   comment: Comment,
331 ): Promise<ResolveObjectResponse> {
332   let form: ResolveObject = {
333     q: comment.ap_id,
334     auth: api.auth,
335   };
336   return api.client.resolveObject(form);
337 }
338
339 export async function resolveBetaCommunity(
340   api: API,
341 ): Promise<ResolveObjectResponse> {
342   // Use short-hand search url
343   let form: ResolveObject = {
344     q: "!main@lemmy-beta:8551",
345     auth: api.auth,
346   };
347   return api.client.resolveObject(form);
348 }
349
350 export async function resolveCommunity(
351   api: API,
352   q: string,
353 ): Promise<ResolveObjectResponse> {
354   let form: ResolveObject = {
355     q,
356     auth: api.auth,
357   };
358   return api.client.resolveObject(form);
359 }
360
361 export async function resolvePerson(
362   api: API,
363   apShortname: string,
364 ): Promise<ResolveObjectResponse> {
365   let form: ResolveObject = {
366     q: apShortname,
367     auth: api.auth,
368   };
369   return api.client.resolveObject(form);
370 }
371
372 export async function banPersonFromSite(
373   api: API,
374   person_id: number,
375   ban: boolean,
376   remove_data: boolean,
377 ): Promise<BanPersonResponse> {
378   // Make sure lemmy-beta/c/main is cached on lemmy_alpha
379   let form: BanPerson = {
380     person_id,
381     ban,
382     remove_data: remove_data,
383     auth: api.auth,
384   };
385   return api.client.banPerson(form);
386 }
387
388 export async function banPersonFromCommunity(
389   api: API,
390   person_id: number,
391   community_id: number,
392   remove_data: boolean,
393   ban: boolean,
394 ): Promise<BanFromCommunityResponse> {
395   let form: BanFromCommunity = {
396     person_id,
397     community_id,
398     remove_data: remove_data,
399     ban,
400     auth: api.auth,
401   };
402   return api.client.banFromCommunity(form);
403 }
404
405 export async function followCommunity(
406   api: API,
407   follow: boolean,
408   community_id: number,
409 ): Promise<CommunityResponse> {
410   let form: FollowCommunity = {
411     community_id,
412     follow,
413     auth: api.auth,
414   };
415   return api.client.followCommunity(form);
416 }
417
418 export async function likePost(
419   api: API,
420   score: number,
421   post: Post,
422 ): Promise<PostResponse> {
423   let form: CreatePostLike = {
424     post_id: post.id,
425     score: score,
426     auth: api.auth,
427   };
428
429   return api.client.likePost(form);
430 }
431
432 export async function createComment(
433   api: API,
434   post_id: number,
435   parent_id?: number,
436   content = "a jest test comment",
437 ): Promise<CommentResponse> {
438   let form: CreateComment = {
439     content,
440     post_id,
441     parent_id,
442     auth: api.auth,
443   };
444   return api.client.createComment(form);
445 }
446
447 export async function editComment(
448   api: API,
449   comment_id: number,
450   content = "A jest test federated comment update",
451 ): Promise<CommentResponse> {
452   let form: EditComment = {
453     content,
454     comment_id,
455     auth: api.auth,
456   };
457   return api.client.editComment(form);
458 }
459
460 export async function deleteComment(
461   api: API,
462   deleted: boolean,
463   comment_id: number,
464 ): Promise<CommentResponse> {
465   let form: DeleteComment = {
466     comment_id,
467     deleted,
468     auth: api.auth,
469   };
470   return api.client.deleteComment(form);
471 }
472
473 export async function removeComment(
474   api: API,
475   removed: boolean,
476   comment_id: number,
477 ): Promise<CommentResponse> {
478   let form: RemoveComment = {
479     comment_id,
480     removed,
481     auth: api.auth,
482   };
483   return api.client.removeComment(form);
484 }
485
486 export async function getMentions(
487   api: API,
488 ): Promise<GetPersonMentionsResponse> {
489   let form: GetPersonMentions = {
490     sort: "New",
491     unread_only: false,
492     auth: api.auth,
493   };
494   return api.client.getPersonMentions(form);
495 }
496
497 export async function likeComment(
498   api: API,
499   score: number,
500   comment: Comment,
501 ): Promise<CommentResponse> {
502   let form: CreateCommentLike = {
503     comment_id: comment.id,
504     score,
505     auth: api.auth,
506   };
507   return api.client.likeComment(form);
508 }
509
510 export async function createCommunity(
511   api: API,
512   name_: string = randomString(5),
513 ): Promise<CommunityResponse> {
514   let description = "a sample description";
515   let form: CreateCommunity = {
516     name: name_,
517     title: name_,
518     description,
519     auth: api.auth,
520   };
521   return api.client.createCommunity(form);
522 }
523
524 export async function getCommunity(
525   api: API,
526   id: number,
527 ): Promise<CommunityResponse> {
528   let form: GetCommunity = {
529     id,
530     auth: api.auth,
531   };
532   return api.client.getCommunity(form);
533 }
534
535 export async function deleteCommunity(
536   api: API,
537   deleted: boolean,
538   community_id: number,
539 ): Promise<CommunityResponse> {
540   let form: DeleteCommunity = {
541     community_id,
542     deleted,
543     auth: api.auth,
544   };
545   return api.client.deleteCommunity(form);
546 }
547
548 export async function removeCommunity(
549   api: API,
550   removed: boolean,
551   community_id: number,
552 ): Promise<CommunityResponse> {
553   let form: RemoveCommunity = {
554     community_id,
555     removed,
556     auth: api.auth,
557   };
558   return api.client.removeCommunity(form);
559 }
560
561 export async function createPrivateMessage(
562   api: API,
563   recipient_id: number,
564 ): Promise<PrivateMessageResponse> {
565   let content = "A jest test federated private message";
566   let form: CreatePrivateMessage = {
567     content,
568     recipient_id,
569     auth: api.auth,
570   };
571   return api.client.createPrivateMessage(form);
572 }
573
574 export async function editPrivateMessage(
575   api: API,
576   private_message_id: number,
577 ): Promise<PrivateMessageResponse> {
578   let updatedContent = "A jest test federated private message edited";
579   let form: EditPrivateMessage = {
580     content: updatedContent,
581     private_message_id,
582     auth: api.auth,
583   };
584   return api.client.editPrivateMessage(form);
585 }
586
587 export async function deletePrivateMessage(
588   api: API,
589   deleted: boolean,
590   private_message_id: number,
591 ): Promise<PrivateMessageResponse> {
592   let form: DeletePrivateMessage = {
593     deleted,
594     private_message_id,
595     auth: api.auth,
596   };
597   return api.client.deletePrivateMessage(form);
598 }
599
600 export async function registerUser(
601   api: API,
602   username: string = randomString(5),
603 ): Promise<LoginResponse> {
604   let form: Register = {
605     username,
606     password,
607     password_verify: password,
608     show_nsfw: true,
609   };
610   return api.client.register(form);
611 }
612
613 export async function saveUserSettingsBio(api: API): Promise<LoginResponse> {
614   let form: SaveUserSettings = {
615     show_nsfw: true,
616     blur_nsfw: false,
617     auto_expand: true,
618     theme: "darkly",
619     default_sort_type: "Active",
620     default_listing_type: "All",
621     interface_language: "en",
622     show_avatars: true,
623     send_notifications_to_email: false,
624     bio: "a changed bio",
625     auth: api.auth,
626   };
627   return saveUserSettings(api, form);
628 }
629
630 export async function saveUserSettingsFederated(
631   api: API,
632 ): Promise<LoginResponse> {
633   let avatar = "https://image.flaticon.com/icons/png/512/35/35896.png";
634   let banner = "https://image.flaticon.com/icons/png/512/36/35896.png";
635   let bio = "a changed bio";
636   let form: SaveUserSettings = {
637     show_nsfw: false,
638     blur_nsfw: true,
639     auto_expand: false,
640     default_sort_type: "Hot",
641     default_listing_type: "All",
642     interface_language: "",
643     avatar,
644     banner,
645     display_name: "user321",
646     show_avatars: false,
647     send_notifications_to_email: false,
648     bio,
649     auth: api.auth,
650   };
651   return await saveUserSettings(alpha, form);
652 }
653
654 export async function saveUserSettings(
655   api: API,
656   form: SaveUserSettings,
657 ): Promise<LoginResponse> {
658   return api.client.saveUserSettings(form);
659 }
660 export async function getPersonDetails(
661   api: API,
662   person_id: number,
663 ): Promise<GetPersonDetailsResponse> {
664   let form: GetPersonDetails = {
665     auth: api.auth,
666     person_id: person_id,
667   };
668   return api.client.getPersonDetails(form);
669 }
670
671 export async function deleteUser(api: API): Promise<DeleteAccountResponse> {
672   let form: DeleteAccount = {
673     auth: api.auth,
674     password,
675   };
676   return api.client.deleteAccount(form);
677 }
678
679 export async function getSite(api: API): Promise<GetSiteResponse> {
680   let form: GetSite = {
681     auth: api.auth,
682   };
683   return api.client.getSite(form);
684 }
685
686 export async function listPrivateMessages(
687   api: API,
688 ): Promise<PrivateMessagesResponse> {
689   let form: GetPrivateMessages = {
690     auth: api.auth,
691     unread_only: false,
692   };
693   return api.client.getPrivateMessages(form);
694 }
695
696 export async function unfollowRemotes(api: API): Promise<GetSiteResponse> {
697   // Unfollow all remote communities
698   let site = await getSite(api);
699   let remoteFollowed =
700     site.my_user?.follows.filter(c => c.community.local == false) ?? [];
701   for (let cu of remoteFollowed) {
702     await followCommunity(api, false, cu.community.id);
703   }
704   let siteRes = await getSite(api);
705   return siteRes;
706 }
707
708 export async function followBeta(api: API): Promise<CommunityResponse> {
709   let betaCommunity = (await resolveBetaCommunity(api)).community;
710   if (betaCommunity) {
711     let follow = await followCommunity(api, true, betaCommunity.community.id);
712     return follow;
713   } else {
714     return Promise.reject("no community worked");
715   }
716 }
717
718 export async function reportPost(
719   api: API,
720   post_id: number,
721   reason: string,
722 ): Promise<PostReportResponse> {
723   let form: CreatePostReport = {
724     post_id,
725     reason,
726     auth: api.auth,
727   };
728   return api.client.createPostReport(form);
729 }
730
731 export async function listPostReports(
732   api: API,
733 ): Promise<ListPostReportsResponse> {
734   let form: ListPostReports = {
735     auth: api.auth,
736   };
737   return api.client.listPostReports(form);
738 }
739
740 export async function reportComment(
741   api: API,
742   comment_id: number,
743   reason: string,
744 ): Promise<CommentReportResponse> {
745   let form: CreateCommentReport = {
746     comment_id,
747     reason,
748     auth: api.auth,
749   };
750   return api.client.createCommentReport(form);
751 }
752
753 export async function listCommentReports(
754   api: API,
755 ): Promise<ListCommentReportsResponse> {
756   let form: ListCommentReports = {
757     auth: api.auth,
758   };
759   return api.client.listCommentReports(form);
760 }
761
762 export function getPosts(
763   api: API,
764   moderator_view = false,
765 ): Promise<GetPostsResponse> {
766   let form: GetPosts = {
767     moderator_view,
768     auth: api.auth,
769   };
770   return api.client.getPosts(form);
771 }
772
773 export function delay(millis = 500) {
774   return new Promise(resolve => setTimeout(resolve, millis));
775 }
776
777 export function longDelay() {
778   return delay(10000);
779 }
780
781 export function wrapper(form: any): string {
782   return JSON.stringify(form);
783 }
784
785 export function randomString(length: number): string {
786   var result = "";
787   var characters =
788     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
789   var charactersLength = characters.length;
790   for (var i = 0; i < length; i++) {
791     result += characters.charAt(Math.floor(Math.random() * charactersLength));
792   }
793   return result;
794 }
795
796 export async function unfollows() {
797   await unfollowRemotes(alpha);
798   await unfollowRemotes(gamma);
799   await unfollowRemotes(delta);
800   await unfollowRemotes(epsilon);
801 }
802
803 export function getCommentParentId(comment: Comment): number | undefined {
804   let split = comment.path.split(".");
805   // remove the 0
806   split.shift();
807
808   if (split.length > 1) {
809     return Number(split[split.length - 2]);
810   } else {
811     return undefined;
812   }
813 }