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