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