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";
37 import { HtmlTags } from "./common/html-tags";
38 import { Spinner } from "./common/icon";
39 import { MomentTime } from "./common/moment-time";
40 import { Paginator } from "./common/paginator";
41 import { CommunityLink } from "./community/community-link";
42 import { PersonListing } from "./person/person-listing";
64 | ModRemoveCommentView
65 | ModRemoveCommunityView
66 | ModBanFromCommunityView
69 | ModTransferCommunityView
74 interface ModlogState {
75 res: GetModlogResponse;
77 communityName?: string;
78 communityMods?: CommunityModeratorView[];
84 export class Modlog extends Component<any, ModlogState> {
85 private isoData = setIsoData(this.context);
86 private subscription: Subscription;
87 private emptyState: ModlogState = {
93 removed_communities: [],
94 banned_from_community: [],
96 added_to_community: [],
97 transferred_to_community: [],
102 site_view: this.isoData.site_res.site_view,
105 constructor(props: any, context: any) {
106 super(props, context);
108 this.state = this.emptyState;
109 this.handlePageChange = this.handlePageChange.bind(this);
111 this.state.communityId = this.props.match.params.community_id
112 ? Number(this.props.match.params.community_id)
115 this.parseMessage = this.parseMessage.bind(this);
116 this.subscription = wsSubscribe(this.parseMessage);
118 // Only fetch the data if coming from another route
119 if (this.isoData.path == this.context.router.route.match.url) {
120 let data = this.isoData.routeData[0];
121 this.state.res = data;
122 this.state.loading = false;
124 // Getting the moderators
125 if (this.isoData.routeData[1]) {
126 this.state.communityMods = this.isoData.routeData[1].moderators;
133 componentWillUnmount() {
135 this.subscription.unsubscribe();
139 buildCombined(res: GetModlogResponse): ModlogType[] {
140 let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
141 id: r.mod_remove_post.id,
142 type_: ModlogEnum.ModRemovePost,
144 when_: r.mod_remove_post.when_,
147 let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
148 id: r.mod_lock_post.id,
149 type_: ModlogEnum.ModLockPost,
151 when_: r.mod_lock_post.when_,
154 let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
155 id: r.mod_sticky_post.id,
156 type_: ModlogEnum.ModStickyPost,
158 when_: r.mod_sticky_post.when_,
161 let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
162 id: r.mod_remove_comment.id,
163 type_: ModlogEnum.ModRemoveComment,
165 when_: r.mod_remove_comment.when_,
168 let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
169 id: r.mod_remove_community.id,
170 type_: ModlogEnum.ModRemoveCommunity,
172 when_: r.mod_remove_community.when_,
175 let banned_from_community: ModlogType[] = res.banned_from_community.map(
177 id: r.mod_ban_from_community.id,
178 type_: ModlogEnum.ModBanFromCommunity,
180 when_: r.mod_ban_from_community.when_,
184 let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
185 id: r.mod_add_community.id,
186 type_: ModlogEnum.ModAddCommunity,
188 when_: r.mod_add_community.when_,
191 let transferred_to_community: ModlogType[] =
192 res.transferred_to_community.map(r => ({
193 id: r.mod_transfer_community.id,
194 type_: ModlogEnum.ModTransferCommunity,
196 when_: r.mod_transfer_community.when_,
199 let added: ModlogType[] = res.added.map(r => ({
201 type_: ModlogEnum.ModAdd,
203 when_: r.mod_add.when_,
206 let banned: ModlogType[] = res.banned.map(r => ({
208 type_: ModlogEnum.ModBan,
210 when_: r.mod_ban.when_,
213 let combined: ModlogType[] = [];
215 combined.push(...removed_posts);
216 combined.push(...locked_posts);
217 combined.push(...stickied_posts);
218 combined.push(...removed_comments);
219 combined.push(...removed_communities);
220 combined.push(...banned_from_community);
221 combined.push(...added_to_community);
222 combined.push(...transferred_to_community);
223 combined.push(...added);
224 combined.push(...banned);
226 if (this.state.communityId && combined.length > 0) {
227 this.state.communityName = (
228 combined[0].view as ModRemovePostView
233 combined.sort((a, b) => b.when_.localeCompare(a.when_));
238 renderModlogType(i: ModlogType) {
240 case ModlogEnum.ModRemovePost: {
241 let mrpv = i.view as ModRemovePostView;
243 mrpv.mod_remove_post.removed ? "Removed " : "Restored ",
245 Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
247 mrpv.mod_remove_post.reason &&
248 ` reason: ${mrpv.mod_remove_post.reason}`,
251 case ModlogEnum.ModLockPost: {
252 let mlpv = i.view as ModLockPostView;
254 mlpv.mod_lock_post.locked ? "Locked " : "Unlocked ",
256 Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
260 case ModlogEnum.ModStickyPost: {
261 let mspv = i.view as ModStickyPostView;
263 mspv.mod_sticky_post.stickied ? "Stickied " : "Unstickied ",
265 Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
269 case ModlogEnum.ModRemoveComment: {
270 let mrc = i.view as ModRemoveCommentView;
272 mrc.mod_remove_comment.removed ? "Removed " : "Restored ",
275 <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
276 {mrc.comment.content}
281 by <PersonListing person={mrc.commenter} />
283 mrc.mod_remove_comment.reason &&
284 ` reason: ${mrc.mod_remove_comment.reason}`,
287 case ModlogEnum.ModRemoveCommunity: {
288 let mrco = i.view as ModRemoveCommunityView;
290 mrco.mod_remove_community.removed ? "Removed " : "Restored ",
292 Community <CommunityLink community={mrco.community} />
294 mrco.mod_remove_community.reason &&
295 ` reason: ${mrco.mod_remove_community.reason}`,
296 mrco.mod_remove_community.expires &&
298 .utc(mrco.mod_remove_community.expires)
302 case ModlogEnum.ModBanFromCommunity: {
303 let mbfc = i.view as ModBanFromCommunityView;
306 {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
309 <PersonListing person={mbfc.banned_person} />
311 <span> from the community </span>,
313 <CommunityLink community={mbfc.community} />
316 {mbfc.mod_ban_from_community.reason &&
317 ` reason: ${mbfc.mod_ban_from_community.reason}`}
320 {mbfc.mod_ban_from_community.expires &&
322 .utc(mbfc.mod_ban_from_community.expires)
327 case ModlogEnum.ModAddCommunity: {
328 let mac = i.view as ModAddCommunityView;
331 {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
334 <PersonListing person={mac.modded_person} />
336 <span> as a mod to the community </span>,
338 <CommunityLink community={mac.community} />
342 case ModlogEnum.ModTransferCommunity: {
343 let mtc = i.view as ModTransferCommunityView;
346 {mtc.mod_transfer_community.removed ? "Removed " : "Transferred "}{" "}
349 <CommunityLink community={mtc.community} />
353 <PersonListing person={mtc.modded_person} />
357 case ModlogEnum.ModBan: {
358 let mb = i.view as ModBanView;
360 <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>,
362 <PersonListing person={mb.banned_person} />
364 <div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
366 {mb.mod_ban.expires &&
367 ` expires: ${moment.utc(mb.mod_ban.expires).fromNow()}`}
371 case ModlogEnum.ModAdd: {
372 let ma = i.view as ModAddView;
374 <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>,
376 <PersonListing person={ma.modded_person} />
378 <span> as an admin </span>,
387 let combined = this.buildCombined(this.state.res);
394 <MomentTime data={i} />
397 {this.isAdminOrMod ? (
398 <PersonListing person={i.view.moderator} />
400 <div>{i18n.t("mod")}</div>
403 <td>{this.renderModlogType(i)}</td>
410 get isAdminOrMod(): boolean {
412 UserService.Instance.localUserView &&
413 this.isoData.site_res.admins
414 .map(a => a.person.id)
415 .includes(UserService.Instance.localUserView.person.id);
417 UserService.Instance.localUserView &&
418 this.state.communityMods &&
419 this.state.communityMods
420 .map(m => m.moderator.id)
421 .includes(UserService.Instance.localUserView.person.id);
422 return isAdmin || isMod;
425 get documentTitle(): string {
426 return `Modlog - ${this.state.site_view.site.name}`;
431 <div class="container">
433 title={this.documentTitle}
434 path={this.context.router.route.match.url}
436 {this.state.loading ? (
443 {this.state.communityName && (
445 className="text-body"
446 to={`/c/${this.state.communityName}`}
448 /c/{this.state.communityName}{" "}
451 <span>{i18n.t("modlog")}</span>
453 <div class="table-responsive">
454 <table id="modlog_table" class="table table-sm table-hover">
455 <thead class="pointer">
457 <th> {i18n.t("time")}</th>
458 <th>{i18n.t("mod")}</th>
459 <th>{i18n.t("action")}</th>
465 page={this.state.page}
466 onChange={this.handlePageChange}
475 handlePageChange(val: number) {
476 this.setState({ page: val });
481 let modlogForm: GetModlog = {
482 community_id: this.state.communityId,
483 page: this.state.page,
486 WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
488 if (this.state.communityId) {
489 let communityForm: GetCommunity = {
490 id: this.state.communityId,
491 name: this.state.communityName,
493 WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
497 static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
498 let pathSplit = req.path.split("/");
499 let communityId = pathSplit[3];
500 let promises: Promise<any>[] = [];
502 let modlogForm: GetModlog = {
508 modlogForm.community_id = Number(communityId);
511 promises.push(req.client.getModlog(modlogForm));
514 let communityForm: GetCommunity = {
515 id: Number(communityId),
517 promises.push(req.client.getCommunity(communityForm));
522 parseMessage(msg: any) {
523 let op = wsUserOp(msg);
526 toast(i18n.t(msg.error), "danger");
528 } else if (op == UserOperation.GetModlog) {
529 let data = wsJsonToRes<GetModlogResponse>(msg).data;
530 this.state.loading = false;
531 window.scrollTo(0, 0);
532 this.state.res = data;
533 this.setState(this.state);
534 } else if (op == UserOperation.GetCommunity) {
535 let data = wsJsonToRes<GetCommunityResponse>(msg).data;
536 this.state.communityMods = data.moderators;