1 import { Component } from "inferno";
2 import { Link } from "inferno-router";
4 CommunityModeratorView,
11 ModBanFromCommunityView,
15 ModRemoveCommunityView,
18 ModTransferCommunityView,
22 } from "lemmy-js-client";
23 import moment from "moment";
24 import { Subscription } from "rxjs";
25 import { i18n } from "../i18next";
26 import { InitialFetchRequest } from "../interfaces";
27 import { UserService, WebSocketService } from "../services";
40 import { HtmlTags } from "./common/html-tags";
41 import { Spinner } from "./common/icon";
42 import { MomentTime } from "./common/moment-time";
43 import { Paginator } from "./common/paginator";
44 import { CommunityLink } from "./community/community-link";
45 import { PersonListing } from "./person/person-listing";
67 | ModRemoveCommentView
68 | ModRemoveCommunityView
69 | ModBanFromCommunityView
72 | ModTransferCommunityView
77 interface ModlogState {
78 res: GetModlogResponse;
80 communityName?: string;
81 communityMods?: CommunityModeratorView[];
87 export class Modlog extends Component<any, ModlogState> {
88 private isoData = setIsoData(this.context);
89 private subscription: Subscription;
90 private emptyState: ModlogState = {
96 removed_communities: [],
97 banned_from_community: [],
99 added_to_community: [],
100 transferred_to_community: [],
105 site_view: this.isoData.site_res.site_view,
108 constructor(props: any, context: any) {
109 super(props, context);
111 this.state = this.emptyState;
112 this.handlePageChange = this.handlePageChange.bind(this);
114 this.state.communityId = this.props.match.params.community_id
115 ? Number(this.props.match.params.community_id)
118 this.parseMessage = this.parseMessage.bind(this);
119 this.subscription = wsSubscribe(this.parseMessage);
121 // Only fetch the data if coming from another route
122 if (this.isoData.path == this.context.router.route.match.url) {
123 let data = this.isoData.routeData[0];
124 this.state.res = data;
125 this.state.loading = false;
127 // Getting the moderators
128 if (this.isoData.routeData[1]) {
129 this.state.communityMods = this.isoData.routeData[1].moderators;
136 componentWillUnmount() {
138 this.subscription.unsubscribe();
142 buildCombined(res: GetModlogResponse): ModlogType[] {
143 let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
144 id: r.mod_remove_post.id,
145 type_: ModlogEnum.ModRemovePost,
147 when_: r.mod_remove_post.when_,
150 let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
151 id: r.mod_lock_post.id,
152 type_: ModlogEnum.ModLockPost,
154 when_: r.mod_lock_post.when_,
157 let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
158 id: r.mod_sticky_post.id,
159 type_: ModlogEnum.ModStickyPost,
161 when_: r.mod_sticky_post.when_,
164 let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
165 id: r.mod_remove_comment.id,
166 type_: ModlogEnum.ModRemoveComment,
168 when_: r.mod_remove_comment.when_,
171 let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
172 id: r.mod_remove_community.id,
173 type_: ModlogEnum.ModRemoveCommunity,
175 when_: r.mod_remove_community.when_,
178 let banned_from_community: ModlogType[] = res.banned_from_community.map(
180 id: r.mod_ban_from_community.id,
181 type_: ModlogEnum.ModBanFromCommunity,
183 when_: r.mod_ban_from_community.when_,
187 let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
188 id: r.mod_add_community.id,
189 type_: ModlogEnum.ModAddCommunity,
191 when_: r.mod_add_community.when_,
194 let transferred_to_community: ModlogType[] =
195 res.transferred_to_community.map(r => ({
196 id: r.mod_transfer_community.id,
197 type_: ModlogEnum.ModTransferCommunity,
199 when_: r.mod_transfer_community.when_,
202 let added: ModlogType[] = res.added.map(r => ({
204 type_: ModlogEnum.ModAdd,
206 when_: r.mod_add.when_,
209 let banned: ModlogType[] = res.banned.map(r => ({
211 type_: ModlogEnum.ModBan,
213 when_: r.mod_ban.when_,
216 let combined: ModlogType[] = [];
218 combined.push(...removed_posts);
219 combined.push(...locked_posts);
220 combined.push(...stickied_posts);
221 combined.push(...removed_comments);
222 combined.push(...removed_communities);
223 combined.push(...banned_from_community);
224 combined.push(...added_to_community);
225 combined.push(...transferred_to_community);
226 combined.push(...added);
227 combined.push(...banned);
229 if (this.state.communityId && combined.length > 0) {
230 this.state.communityName = (
231 combined[0].view as ModRemovePostView
236 combined.sort((a, b) => b.when_.localeCompare(a.when_));
241 renderModlogType(i: ModlogType) {
243 case ModlogEnum.ModRemovePost: {
244 let mrpv = i.view as ModRemovePostView;
246 mrpv.mod_remove_post.removed ? "Removed " : "Restored ",
248 Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
250 mrpv.mod_remove_post.reason &&
251 ` reason: ${mrpv.mod_remove_post.reason}`,
254 case ModlogEnum.ModLockPost: {
255 let mlpv = i.view as ModLockPostView;
257 mlpv.mod_lock_post.locked ? "Locked " : "Unlocked ",
259 Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
263 case ModlogEnum.ModStickyPost: {
264 let mspv = i.view as ModStickyPostView;
266 mspv.mod_sticky_post.stickied ? "Stickied " : "Unstickied ",
268 Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
272 case ModlogEnum.ModRemoveComment: {
273 let mrc = i.view as ModRemoveCommentView;
275 mrc.mod_remove_comment.removed ? "Removed " : "Restored ",
278 <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
279 {mrc.comment.content}
284 by <PersonListing person={mrc.commenter} />
286 mrc.mod_remove_comment.reason &&
287 ` reason: ${mrc.mod_remove_comment.reason}`,
290 case ModlogEnum.ModRemoveCommunity: {
291 let mrco = i.view as ModRemoveCommunityView;
293 mrco.mod_remove_community.removed ? "Removed " : "Restored ",
295 Community <CommunityLink community={mrco.community} />
297 mrco.mod_remove_community.reason &&
298 ` reason: ${mrco.mod_remove_community.reason}`,
299 mrco.mod_remove_community.expires &&
301 .utc(mrco.mod_remove_community.expires)
305 case ModlogEnum.ModBanFromCommunity: {
306 let mbfc = i.view as ModBanFromCommunityView;
309 {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
312 <PersonListing person={mbfc.banned_person} />
314 <span> from the community </span>,
316 <CommunityLink community={mbfc.community} />
319 {mbfc.mod_ban_from_community.reason &&
320 ` reason: ${mbfc.mod_ban_from_community.reason}`}
323 {mbfc.mod_ban_from_community.expires &&
325 .utc(mbfc.mod_ban_from_community.expires)
330 case ModlogEnum.ModAddCommunity: {
331 let mac = i.view as ModAddCommunityView;
334 {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
337 <PersonListing person={mac.modded_person} />
339 <span> as a mod to the community </span>,
341 <CommunityLink community={mac.community} />
345 case ModlogEnum.ModTransferCommunity: {
346 let mtc = i.view as ModTransferCommunityView;
349 {mtc.mod_transfer_community.removed ? "Removed " : "Transferred "}{" "}
352 <CommunityLink community={mtc.community} />
356 <PersonListing person={mtc.modded_person} />
360 case ModlogEnum.ModBan: {
361 let mb = i.view as ModBanView;
363 <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>,
365 <PersonListing person={mb.banned_person} />
367 <div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
369 {mb.mod_ban.expires &&
370 ` expires: ${moment.utc(mb.mod_ban.expires).fromNow()}`}
374 case ModlogEnum.ModAdd: {
375 let ma = i.view as ModAddView;
377 <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>,
379 <PersonListing person={ma.modded_person} />
381 <span> as an admin </span>,
390 let combined = this.buildCombined(this.state.res);
397 <MomentTime data={i} />
400 {this.isAdminOrMod ? (
401 <PersonListing person={i.view.moderator} />
403 <div>{this.modOrAdminText(i.view.moderator)}</div>
406 <td>{this.renderModlogType(i)}</td>
413 get isAdminOrMod(): boolean {
415 UserService.Instance.myUserInfo &&
416 this.isoData.site_res.admins
417 .map(a => a.person.id)
418 .includes(UserService.Instance.myUserInfo.local_user_view.person.id);
420 UserService.Instance.myUserInfo &&
421 this.state.communityMods &&
422 this.state.communityMods
423 .map(m => m.moderator.id)
424 .includes(UserService.Instance.myUserInfo.local_user_view.person.id);
425 return isAdmin || isMod;
428 modOrAdminText(person: PersonSafe): Text {
430 this.isoData.site_res.admins.map(a => a.person.id).includes(person.id)
432 return i18n.t("admin");
434 return i18n.t("mod");
438 get documentTitle(): string {
439 return `Modlog - ${this.state.site_view.site.name}`;
444 <div class="container">
446 title={this.documentTitle}
447 path={this.context.router.route.match.url}
449 {this.state.loading ? (
456 {this.state.communityName && (
458 className="text-body"
459 to={`/c/${this.state.communityName}`}
461 /c/{this.state.communityName}{" "}
464 <span>{i18n.t("modlog")}</span>
466 <div class="table-responsive">
467 <table id="modlog_table" class="table table-sm table-hover">
468 <thead class="pointer">
470 <th> {i18n.t("time")}</th>
471 <th>{i18n.t("mod")}</th>
472 <th>{i18n.t("action")}</th>
478 page={this.state.page}
479 onChange={this.handlePageChange}
488 handlePageChange(val: number) {
489 this.setState({ page: val });
494 let modlogForm: GetModlog = {
495 community_id: this.state.communityId,
496 page: this.state.page,
498 auth: authField(false),
500 WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
502 if (this.state.communityId) {
503 let communityForm: GetCommunity = {
504 id: this.state.communityId,
505 name: this.state.communityName,
507 WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
511 static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
512 let pathSplit = req.path.split("/");
513 let communityId = pathSplit[3];
514 let promises: Promise<any>[] = [];
516 let modlogForm: GetModlog = {
522 modlogForm.community_id = Number(communityId);
524 setOptionalAuth(modlogForm, req.auth);
526 promises.push(req.client.getModlog(modlogForm));
529 let communityForm: GetCommunity = {
530 id: Number(communityId),
532 setOptionalAuth(communityForm, req.auth);
533 promises.push(req.client.getCommunity(communityForm));
538 parseMessage(msg: any) {
539 let op = wsUserOp(msg);
542 toast(i18n.t(msg.error), "danger");
544 } else if (op == UserOperation.GetModlog) {
545 let data = wsJsonToRes<GetModlogResponse>(msg).data;
546 this.state.loading = false;
547 window.scrollTo(0, 0);
548 this.state.res = data;
549 this.setState(this.state);
550 } else if (op == UserOperation.GetCommunity) {
551 let data = wsJsonToRes<GetCommunityResponse>(msg).data;
552 this.state.communityMods = data.moderators;