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