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