1 import { Component } from "inferno";
2 import { Link } from "inferno-router";
4 CommunityModeratorView,
11 ModBanFromCommunityView,
15 ModRemoveCommunityView,
18 ModTransferCommunityView,
21 } from "lemmy-js-client";
22 import moment from "moment";
23 import { Subscription } from "rxjs";
24 import { i18n } from "../i18next";
25 import { InitialFetchRequest } from "../interfaces";
26 import { UserService, WebSocketService } from "../services";
39 import { HtmlTags } from "./common/html-tags";
40 import { Spinner } from "./common/icon";
41 import { MomentTime } from "./common/moment-time";
42 import { Paginator } from "./common/paginator";
43 import { CommunityLink } from "./community/community-link";
44 import { PersonListing } from "./person/person-listing";
66 | ModRemoveCommentView
67 | ModRemoveCommunityView
68 | ModBanFromCommunityView
71 | ModTransferCommunityView
76 interface ModlogState {
77 res: GetModlogResponse;
79 communityName?: string;
80 communityMods?: CommunityModeratorView[];
86 export class Modlog extends Component<any, ModlogState> {
87 private isoData = setIsoData(this.context);
88 private subscription: Subscription;
89 private emptyState: ModlogState = {
95 removed_communities: [],
96 banned_from_community: [],
98 added_to_community: [],
99 transferred_to_community: [],
104 site_view: this.isoData.site_res.site_view,
107 constructor(props: any, context: any) {
108 super(props, context);
110 this.state = this.emptyState;
111 this.handlePageChange = this.handlePageChange.bind(this);
113 this.state.communityId = this.props.match.params.community_id
114 ? Number(this.props.match.params.community_id)
117 this.parseMessage = this.parseMessage.bind(this);
118 this.subscription = wsSubscribe(this.parseMessage);
120 // Only fetch the data if coming from another route
121 if (this.isoData.path == this.context.router.route.match.url) {
122 let data = this.isoData.routeData[0];
123 this.state.res = data;
124 this.state.loading = false;
126 // Getting the moderators
127 if (this.isoData.routeData[1]) {
128 this.state.communityMods = this.isoData.routeData[1].moderators;
135 componentWillUnmount() {
137 this.subscription.unsubscribe();
141 buildCombined(res: GetModlogResponse): ModlogType[] {
142 let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
143 id: r.mod_remove_post.id,
144 type_: ModlogEnum.ModRemovePost,
146 when_: r.mod_remove_post.when_,
149 let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
150 id: r.mod_lock_post.id,
151 type_: ModlogEnum.ModLockPost,
153 when_: r.mod_lock_post.when_,
156 let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
157 id: r.mod_sticky_post.id,
158 type_: ModlogEnum.ModStickyPost,
160 when_: r.mod_sticky_post.when_,
163 let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
164 id: r.mod_remove_comment.id,
165 type_: ModlogEnum.ModRemoveComment,
167 when_: r.mod_remove_comment.when_,
170 let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
171 id: r.mod_remove_community.id,
172 type_: ModlogEnum.ModRemoveCommunity,
174 when_: r.mod_remove_community.when_,
177 let banned_from_community: ModlogType[] = res.banned_from_community.map(
179 id: r.mod_ban_from_community.id,
180 type_: ModlogEnum.ModBanFromCommunity,
182 when_: r.mod_ban_from_community.when_,
186 let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
187 id: r.mod_add_community.id,
188 type_: ModlogEnum.ModAddCommunity,
190 when_: r.mod_add_community.when_,
193 let transferred_to_community: ModlogType[] =
194 res.transferred_to_community.map(r => ({
195 id: r.mod_transfer_community.id,
196 type_: ModlogEnum.ModTransferCommunity,
198 when_: r.mod_transfer_community.when_,
201 let added: ModlogType[] = res.added.map(r => ({
203 type_: ModlogEnum.ModAdd,
205 when_: r.mod_add.when_,
208 let banned: ModlogType[] = res.banned.map(r => ({
210 type_: ModlogEnum.ModBan,
212 when_: r.mod_ban.when_,
215 let combined: ModlogType[] = [];
217 combined.push(...removed_posts);
218 combined.push(...locked_posts);
219 combined.push(...stickied_posts);
220 combined.push(...removed_comments);
221 combined.push(...removed_communities);
222 combined.push(...banned_from_community);
223 combined.push(...added_to_community);
224 combined.push(...transferred_to_community);
225 combined.push(...added);
226 combined.push(...banned);
228 if (this.state.communityId && combined.length > 0) {
229 this.state.communityName = (
230 combined[0].view as ModRemovePostView
235 combined.sort((a, b) => b.when_.localeCompare(a.when_));
240 renderModlogType(i: ModlogType) {
242 case ModlogEnum.ModRemovePost: {
243 let mrpv = i.view as ModRemovePostView;
245 mrpv.mod_remove_post.removed ? "Removed " : "Restored ",
247 Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
249 mrpv.mod_remove_post.reason &&
250 ` reason: ${mrpv.mod_remove_post.reason}`,
253 case ModlogEnum.ModLockPost: {
254 let mlpv = i.view as ModLockPostView;
256 mlpv.mod_lock_post.locked ? "Locked " : "Unlocked ",
258 Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
262 case ModlogEnum.ModStickyPost: {
263 let mspv = i.view as ModStickyPostView;
265 mspv.mod_sticky_post.stickied ? "Stickied " : "Unstickied ",
267 Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
271 case ModlogEnum.ModRemoveComment: {
272 let mrc = i.view as ModRemoveCommentView;
274 mrc.mod_remove_comment.removed ? "Removed " : "Restored ",
277 <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
278 {mrc.comment.content}
283 by <PersonListing person={mrc.commenter} />
285 mrc.mod_remove_comment.reason &&
286 ` reason: ${mrc.mod_remove_comment.reason}`,
289 case ModlogEnum.ModRemoveCommunity: {
290 let mrco = i.view as ModRemoveCommunityView;
292 mrco.mod_remove_community.removed ? "Removed " : "Restored ",
294 Community <CommunityLink community={mrco.community} />
296 mrco.mod_remove_community.reason &&
297 ` reason: ${mrco.mod_remove_community.reason}`,
298 mrco.mod_remove_community.expires &&
300 .utc(mrco.mod_remove_community.expires)
304 case ModlogEnum.ModBanFromCommunity: {
305 let mbfc = i.view as ModBanFromCommunityView;
308 {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
311 <PersonListing person={mbfc.banned_person} />
313 <span> from the community </span>,
315 <CommunityLink community={mbfc.community} />
318 {mbfc.mod_ban_from_community.reason &&
319 ` reason: ${mbfc.mod_ban_from_community.reason}`}
322 {mbfc.mod_ban_from_community.expires &&
324 .utc(mbfc.mod_ban_from_community.expires)
329 case ModlogEnum.ModAddCommunity: {
330 let mac = i.view as ModAddCommunityView;
333 {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
336 <PersonListing person={mac.modded_person} />
338 <span> as a mod to the community </span>,
340 <CommunityLink community={mac.community} />
344 case ModlogEnum.ModTransferCommunity: {
345 let mtc = i.view as ModTransferCommunityView;
348 {mtc.mod_transfer_community.removed ? "Removed " : "Transferred "}{" "}
351 <CommunityLink community={mtc.community} />
355 <PersonListing person={mtc.modded_person} />
359 case ModlogEnum.ModBan: {
360 let mb = i.view as ModBanView;
362 <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>,
364 <PersonListing person={mb.banned_person} />
366 <div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
368 {mb.mod_ban.expires &&
369 ` expires: ${moment.utc(mb.mod_ban.expires).fromNow()}`}
373 case ModlogEnum.ModAdd: {
374 let ma = i.view as ModAddView;
376 <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>,
378 <PersonListing person={ma.modded_person} />
380 <span> as an admin </span>,
389 let combined = this.buildCombined(this.state.res);
396 <MomentTime data={i} />
399 {this.isAdminOrMod ? (
400 <PersonListing person={i.view.moderator} />
402 <div>{i18n.t("mod")}</div>
405 <td>{this.renderModlogType(i)}</td>
412 get isAdminOrMod(): boolean {
414 UserService.Instance.myUserInfo &&
415 this.isoData.site_res.admins
416 .map(a => a.person.id)
417 .includes(UserService.Instance.myUserInfo.local_user_view.person.id);
419 UserService.Instance.myUserInfo &&
420 this.state.communityMods &&
421 this.state.communityMods
422 .map(m => m.moderator.id)
423 .includes(UserService.Instance.myUserInfo.local_user_view.person.id);
424 return isAdmin || isMod;
427 get documentTitle(): string {
428 return `Modlog - ${this.state.site_view.site.name}`;
433 <div class="container">
435 title={this.documentTitle}
436 path={this.context.router.route.match.url}
438 {this.state.loading ? (
445 {this.state.communityName && (
447 className="text-body"
448 to={`/c/${this.state.communityName}`}
450 /c/{this.state.communityName}{" "}
453 <span>{i18n.t("modlog")}</span>
455 <div class="table-responsive">
456 <table id="modlog_table" class="table table-sm table-hover">
457 <thead class="pointer">
459 <th> {i18n.t("time")}</th>
460 <th>{i18n.t("mod")}</th>
461 <th>{i18n.t("action")}</th>
467 page={this.state.page}
468 onChange={this.handlePageChange}
477 handlePageChange(val: number) {
478 this.setState({ page: val });
483 let modlogForm: GetModlog = {
484 community_id: this.state.communityId,
485 page: this.state.page,
487 auth: authField(false),
489 WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
491 if (this.state.communityId) {
492 let communityForm: GetCommunity = {
493 id: this.state.communityId,
494 name: this.state.communityName,
496 WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
500 static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
501 let pathSplit = req.path.split("/");
502 let communityId = pathSplit[3];
503 let promises: Promise<any>[] = [];
505 let modlogForm: GetModlog = {
511 modlogForm.community_id = Number(communityId);
513 setOptionalAuth(modlogForm, req.auth);
515 promises.push(req.client.getModlog(modlogForm));
518 let communityForm: GetCommunity = {
519 id: Number(communityId),
521 setOptionalAuth(communityForm, req.auth);
522 promises.push(req.client.getCommunity(communityForm));
527 parseMessage(msg: any) {
528 let op = wsUserOp(msg);
531 toast(i18n.t(msg.error), "danger");
533 } else if (op == UserOperation.GetModlog) {
534 let data = wsJsonToRes<GetModlogResponse>(msg).data;
535 this.state.loading = false;
536 window.scrollTo(0, 0);
537 this.state.res = data;
538 this.setState(this.state);
539 } else if (op == UserOperation.GetCommunity) {
540 let data = wsJsonToRes<GetCommunityResponse>(msg).data;
541 this.state.communityMods = data.moderators;