]> Untitled Git - lemmy-ui.git/blob - src/shared/components/modlog.tsx
Copy forward-headers from nginx to local node-fetch. Fixes #73
[lemmy-ui.git] / src / shared / components / modlog.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
3 import { Subscription } from 'rxjs';
4 import {
5   UserOperation,
6   GetModlogForm,
7   GetModlogResponse,
8   ModRemovePost,
9   ModLockPost,
10   ModStickyPost,
11   ModRemoveComment,
12   ModRemoveCommunity,
13   ModBanFromCommunity,
14   ModBan,
15   ModAddCommunity,
16   ModAdd,
17   WebSocketJsonResponse,
18   Site,
19 } from 'lemmy-js-client';
20 import { WebSocketService } from '../services';
21 import {
22   wsJsonToRes,
23   addTypeInfo,
24   fetchLimit,
25   toast,
26   setIsoData,
27   wsSubscribe,
28   isBrowser,
29 } from '../utils';
30 import { MomentTime } from './moment-time';
31 import { HtmlTags } from './html-tags';
32 import moment from 'moment';
33 import { i18n } from '../i18next';
34 import { InitialFetchRequest } from 'shared/interfaces';
35
36 interface ModlogState {
37   combined: {
38     type_: string;
39     data:
40       | ModRemovePost
41       | ModLockPost
42       | ModStickyPost
43       | ModRemoveCommunity
44       | ModAdd
45       | ModBan;
46   }[];
47   communityId?: number;
48   communityName?: string;
49   page: number;
50   site: Site;
51   loading: boolean;
52 }
53
54 export class Modlog extends Component<any, ModlogState> {
55   private isoData = setIsoData(this.context);
56   private subscription: Subscription;
57   private emptyState: ModlogState = {
58     combined: [],
59     page: 1,
60     loading: true,
61     site: this.isoData.site.site,
62   };
63
64   constructor(props: any, context: any) {
65     super(props, context);
66
67     this.state = this.emptyState;
68     this.state.communityId = this.props.match.params.community_id
69       ? Number(this.props.match.params.community_id)
70       : undefined;
71
72     this.parseMessage = this.parseMessage.bind(this);
73     this.subscription = wsSubscribe(this.parseMessage);
74
75     // Only fetch the data if coming from another route
76     if (this.isoData.path == this.context.router.route.match.url) {
77       let data = this.isoData.routeData[0];
78       this.setCombined(data);
79       this.state.loading = false;
80     } else {
81       this.refetch();
82     }
83   }
84
85   componentWillUnmount() {
86     if (isBrowser()) {
87       this.subscription.unsubscribe();
88     }
89   }
90
91   setCombined(res: GetModlogResponse) {
92     let removed_posts = addTypeInfo(res.removed_posts, 'removed_posts');
93     let locked_posts = addTypeInfo(res.locked_posts, 'locked_posts');
94     let stickied_posts = addTypeInfo(res.stickied_posts, 'stickied_posts');
95     let removed_comments = addTypeInfo(
96       res.removed_comments,
97       'removed_comments'
98     );
99     let removed_communities = addTypeInfo(
100       res.removed_communities,
101       'removed_communities'
102     );
103     let banned_from_community = addTypeInfo(
104       res.banned_from_community,
105       'banned_from_community'
106     );
107     let added_to_community = addTypeInfo(
108       res.added_to_community,
109       'added_to_community'
110     );
111     let added = addTypeInfo(res.added, 'added');
112     let banned = addTypeInfo(res.banned, 'banned');
113     this.state.combined = [];
114
115     this.state.combined.push(...removed_posts);
116     this.state.combined.push(...locked_posts);
117     this.state.combined.push(...stickied_posts);
118     this.state.combined.push(...removed_comments);
119     this.state.combined.push(...removed_communities);
120     this.state.combined.push(...banned_from_community);
121     this.state.combined.push(...added_to_community);
122     this.state.combined.push(...added);
123     this.state.combined.push(...banned);
124
125     if (this.state.communityId && this.state.combined.length > 0) {
126       this.state.communityName = (this.state.combined[0]
127         .data as ModRemovePost).community_name;
128     }
129
130     // Sort them by time
131     this.state.combined.sort((a, b) =>
132       b.data.when_.localeCompare(a.data.when_)
133     );
134   }
135
136   combined() {
137     return (
138       <tbody>
139         {this.state.combined.map(i => (
140           <tr>
141             <td>
142               <MomentTime data={i.data} />
143             </td>
144             <td>
145               <Link to={`/u/${i.data.mod_user_name}`}>
146                 {i.data.mod_user_name}
147               </Link>
148             </td>
149             <td>
150               {i.type_ == 'removed_posts' && (
151                 <>
152                   {(i.data as ModRemovePost).removed ? 'Removed' : 'Restored'}
153                   <span>
154                     {' '}
155                     Post{' '}
156                     <Link to={`/post/${(i.data as ModRemovePost).post_id}`}>
157                       {(i.data as ModRemovePost).post_name}
158                     </Link>
159                   </span>
160                   <div>
161                     {(i.data as ModRemovePost).reason &&
162                       ` reason: ${(i.data as ModRemovePost).reason}`}
163                   </div>
164                 </>
165               )}
166               {i.type_ == 'locked_posts' && (
167                 <>
168                   {(i.data as ModLockPost).locked ? 'Locked' : 'Unlocked'}
169                   <span>
170                     {' '}
171                     Post{' '}
172                     <Link to={`/post/${(i.data as ModLockPost).post_id}`}>
173                       {(i.data as ModLockPost).post_name}
174                     </Link>
175                   </span>
176                 </>
177               )}
178               {i.type_ == 'stickied_posts' && (
179                 <>
180                   {(i.data as ModStickyPost).stickied
181                     ? 'Stickied'
182                     : 'Unstickied'}
183                   <span>
184                     {' '}
185                     Post{' '}
186                     <Link to={`/post/${(i.data as ModStickyPost).post_id}`}>
187                       {(i.data as ModStickyPost).post_name}
188                     </Link>
189                   </span>
190                 </>
191               )}
192               {i.type_ == 'removed_comments' && (
193                 <>
194                   {(i.data as ModRemoveComment).removed
195                     ? 'Removed'
196                     : 'Restored'}
197                   <span>
198                     {' '}
199                     Comment{' '}
200                     <Link
201                       to={`/post/${
202                         (i.data as ModRemoveComment).post_id
203                       }/comment/${(i.data as ModRemoveComment).comment_id}`}
204                     >
205                       {(i.data as ModRemoveComment).comment_content}
206                     </Link>
207                   </span>
208                   <span>
209                     {' '}
210                     by{' '}
211                     <Link
212                       to={`/u/${
213                         (i.data as ModRemoveComment).comment_user_name
214                       }`}
215                     >
216                       {(i.data as ModRemoveComment).comment_user_name}
217                     </Link>
218                   </span>
219                   <div>
220                     {(i.data as ModRemoveComment).reason &&
221                       ` reason: ${(i.data as ModRemoveComment).reason}`}
222                   </div>
223                 </>
224               )}
225               {i.type_ == 'removed_communities' && (
226                 <>
227                   {(i.data as ModRemoveCommunity).removed
228                     ? 'Removed'
229                     : 'Restored'}
230                   <span>
231                     {' '}
232                     Community{' '}
233                     <Link
234                       to={`/c/${(i.data as ModRemoveCommunity).community_name}`}
235                     >
236                       {(i.data as ModRemoveCommunity).community_name}
237                     </Link>
238                   </span>
239                   <div>
240                     {(i.data as ModRemoveCommunity).reason &&
241                       ` reason: ${(i.data as ModRemoveCommunity).reason}`}
242                   </div>
243                   <div>
244                     {(i.data as ModRemoveCommunity).expires &&
245                       ` expires: ${moment
246                         .utc((i.data as ModRemoveCommunity).expires)
247                         .fromNow()}`}
248                   </div>
249                 </>
250               )}
251               {i.type_ == 'banned_from_community' && (
252                 <>
253                   <span>
254                     {(i.data as ModBanFromCommunity).banned
255                       ? 'Banned '
256                       : 'Unbanned '}{' '}
257                   </span>
258                   <span>
259                     <Link
260                       to={`/u/${
261                         (i.data as ModBanFromCommunity).other_user_name
262                       }`}
263                     >
264                       {(i.data as ModBanFromCommunity).other_user_name}
265                     </Link>
266                   </span>
267                   <span> from the community </span>
268                   <span>
269                     <Link
270                       to={`/c/${
271                         (i.data as ModBanFromCommunity).community_name
272                       }`}
273                     >
274                       {(i.data as ModBanFromCommunity).community_name}
275                     </Link>
276                   </span>
277                   <div>
278                     {(i.data as ModBanFromCommunity).reason &&
279                       ` reason: ${(i.data as ModBanFromCommunity).reason}`}
280                   </div>
281                   <div>
282                     {(i.data as ModBanFromCommunity).expires &&
283                       ` expires: ${moment
284                         .utc((i.data as ModBanFromCommunity).expires)
285                         .fromNow()}`}
286                   </div>
287                 </>
288               )}
289               {i.type_ == 'added_to_community' && (
290                 <>
291                   <span>
292                     {(i.data as ModAddCommunity).removed
293                       ? 'Removed '
294                       : 'Appointed '}{' '}
295                   </span>
296                   <span>
297                     <Link
298                       to={`/u/${(i.data as ModAddCommunity).other_user_name}`}
299                     >
300                       {(i.data as ModAddCommunity).other_user_name}
301                     </Link>
302                   </span>
303                   <span> as a mod to the community </span>
304                   <span>
305                     <Link
306                       to={`/c/${(i.data as ModAddCommunity).community_name}`}
307                     >
308                       {(i.data as ModAddCommunity).community_name}
309                     </Link>
310                   </span>
311                 </>
312               )}
313               {i.type_ == 'banned' && (
314                 <>
315                   <span>
316                     {(i.data as ModBan).banned ? 'Banned ' : 'Unbanned '}{' '}
317                   </span>
318                   <span>
319                     <Link to={`/u/${(i.data as ModBan).other_user_name}`}>
320                       {(i.data as ModBan).other_user_name}
321                     </Link>
322                   </span>
323                   <div>
324                     {(i.data as ModBan).reason &&
325                       ` reason: ${(i.data as ModBan).reason}`}
326                   </div>
327                   <div>
328                     {(i.data as ModBan).expires &&
329                       ` expires: ${moment
330                         .utc((i.data as ModBan).expires)
331                         .fromNow()}`}
332                   </div>
333                 </>
334               )}
335               {i.type_ == 'added' && (
336                 <>
337                   <span>
338                     {(i.data as ModAdd).removed ? 'Removed ' : 'Appointed '}{' '}
339                   </span>
340                   <span>
341                     <Link to={`/u/${(i.data as ModAdd).other_user_name}`}>
342                       {(i.data as ModAdd).other_user_name}
343                     </Link>
344                   </span>
345                   <span> as an admin </span>
346                 </>
347               )}
348             </td>
349           </tr>
350         ))}
351       </tbody>
352     );
353   }
354
355   get documentTitle(): string {
356     return `Modlog - ${this.state.site.name}`;
357   }
358
359   render() {
360     return (
361       <div class="container">
362         <HtmlTags
363           title={this.documentTitle}
364           path={this.context.router.route.match.url}
365         />
366         {this.state.loading ? (
367           <h5 class="">
368             <svg class="icon icon-spinner spin">
369               <use xlinkHref="#icon-spinner"></use>
370             </svg>
371           </h5>
372         ) : (
373           <div>
374             <h5>
375               {this.state.communityName && (
376                 <Link
377                   className="text-body"
378                   to={`/c/${this.state.communityName}`}
379                 >
380                   /c/{this.state.communityName}{' '}
381                 </Link>
382               )}
383               <span>{i18n.t('modlog')}</span>
384             </h5>
385             <div class="table-responsive">
386               <table id="modlog_table" class="table table-sm table-hover">
387                 <thead class="pointer">
388                   <tr>
389                     <th> {i18n.t('time')}</th>
390                     <th>{i18n.t('mod')}</th>
391                     <th>{i18n.t('action')}</th>
392                   </tr>
393                 </thead>
394                 {this.combined()}
395               </table>
396               {this.paginator()}
397             </div>
398           </div>
399         )}
400       </div>
401     );
402   }
403
404   paginator() {
405     return (
406       <div class="mt-2">
407         {this.state.page > 1 && (
408           <button
409             class="btn btn-secondary mr-1"
410             onClick={linkEvent(this, this.prevPage)}
411           >
412             {i18n.t('prev')}
413           </button>
414         )}
415         <button
416           class="btn btn-secondary"
417           onClick={linkEvent(this, this.nextPage)}
418         >
419           {i18n.t('next')}
420         </button>
421       </div>
422     );
423   }
424
425   nextPage(i: Modlog) {
426     i.state.page++;
427     i.setState(i.state);
428     i.refetch();
429   }
430
431   prevPage(i: Modlog) {
432     i.state.page--;
433     i.setState(i.state);
434     i.refetch();
435   }
436
437   refetch() {
438     let modlogForm: GetModlogForm = {
439       community_id: this.state.communityId,
440       page: this.state.page,
441       limit: fetchLimit,
442     };
443     WebSocketService.Instance.getModlog(modlogForm);
444   }
445
446   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
447     let pathSplit = req.path.split('/');
448     let communityId = pathSplit[3];
449     let promises: Promise<any>[] = [];
450
451     let modlogForm: GetModlogForm = {
452       page: 1,
453       limit: fetchLimit,
454     };
455
456     if (communityId) {
457       modlogForm.community_id = Number(communityId);
458     }
459
460     promises.push(req.client.getModlog(modlogForm));
461     return promises;
462   }
463
464   parseMessage(msg: WebSocketJsonResponse) {
465     console.log(msg);
466     let res = wsJsonToRes(msg);
467     if (msg.error) {
468       toast(i18n.t(msg.error), 'danger');
469       return;
470     } else if (res.op == UserOperation.GetModlog) {
471       let data = res.data as GetModlogResponse;
472       this.state.loading = false;
473       window.scrollTo(0, 0);
474       this.setCombined(data);
475       this.setState(this.state);
476     }
477   }
478 }