Adding site ban from profile page. Fixes #588

This commit is contained in:
Dessalines 2022-04-15 14:56:27 -04:00
parent 47a0b8d4b9
commit bd3d7f72f3
2 changed files with 197 additions and 6 deletions

View file

@ -2,6 +2,7 @@ import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { import {
AddAdminResponse, AddAdminResponse,
BanPerson,
BanPersonResponse, BanPersonResponse,
BlockPerson, BlockPerson,
BlockPersonResponse, BlockPersonResponse,
@ -20,12 +21,17 @@ import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
authField, authField,
canMod,
capitalizeFirstLetter,
createCommentLikeRes, createCommentLikeRes,
createPostLikeFindRes, createPostLikeFindRes,
editCommentRes, editCommentRes,
editPostFindRes, editPostFindRes,
fetchLimit, fetchLimit,
futureDaysToUnixTime,
getUsernameFromProps, getUsernameFromProps,
isBanned,
isMod,
mdToHtml, mdToHtml,
numToSI, numToSI,
previewLines, previewLines,
@ -62,6 +68,10 @@ interface ProfileState {
loading: boolean; loading: boolean;
personBlocked: boolean; personBlocked: boolean;
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
showBanDialog: boolean;
banReason: string;
banExpireDays: number;
removeData: boolean;
} }
interface ProfileProps { interface ProfileProps {
@ -90,6 +100,10 @@ export class Profile extends Component<any, ProfileState> {
page: Profile.getPageFromProps(this.props.match.page), page: Profile.getPageFromProps(this.props.match.page),
personBlocked: false, personBlocked: false,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
showBanDialog: false,
banReason: null,
banExpireDays: null,
removeData: false,
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -128,7 +142,7 @@ export class Profile extends Component<any, ProfileState> {
get isCurrentUser() { get isCurrentUser() {
return ( return (
UserService.Instance.myUserInfo?.local_user_view.person.id == UserService.Instance.myUserInfo?.local_user_view.person.id ==
this.state.personRes.person_view.person.id this.state.personRes?.person_view.person.id
); );
} }
@ -379,7 +393,7 @@ export class Profile extends Component<any, ProfileState> {
hideAvatar hideAvatar
/> />
</li> </li>
{pv.person.banned && ( {isBanned(pv.person) && (
<li className="list-inline-item badge badge-danger"> <li className="list-inline-item badge badge-danger">
{i18n.t("banned")} {i18n.t("banned")}
</li> </li>
@ -396,6 +410,7 @@ export class Profile extends Component<any, ProfileState> {
)} )}
</ul> </ul>
</div> </div>
{this.banDialog()}
<div className="flex-grow-1 unselectable pointer mx-2"></div> <div className="flex-grow-1 unselectable pointer mx-2"></div>
{!this.isCurrentUser && UserService.Instance.myUserInfo && ( {!this.isCurrentUser && UserService.Instance.myUserInfo && (
<> <>
@ -416,7 +431,9 @@ export class Profile extends Component<any, ProfileState> {
</Link> </Link>
{this.state.personBlocked ? ( {this.state.personBlocked ? (
<button <button
className={"d-flex align-self-start btn btn-secondary"} className={
"d-flex align-self-start btn btn-secondary mr-2"
}
onClick={linkEvent( onClick={linkEvent(
pv.person.id, pv.person.id,
this.handleUnblockPerson this.handleUnblockPerson
@ -426,7 +443,9 @@ export class Profile extends Component<any, ProfileState> {
</button> </button>
) : ( ) : (
<button <button
className={"d-flex align-self-start btn btn-secondary"} className={
"d-flex align-self-start btn btn-secondary mr-2"
}
onClick={linkEvent(pv.person.id, this.handleBlockPerson)} onClick={linkEvent(pv.person.id, this.handleBlockPerson)}
> >
{i18n.t("block_user")} {i18n.t("block_user")}
@ -434,6 +453,27 @@ export class Profile extends Component<any, ProfileState> {
)} )}
</> </>
)} )}
{this.canAdmin &&
!this.personIsAdmin &&
!this.state.showBanDialog &&
(!isBanned(pv.person) ? (
<button
className={"d-flex align-self-start btn btn-secondary mr-2"}
onClick={linkEvent(this, this.handleModBanShow)}
aria-label={i18n.t("ban")}
>
{capitalizeFirstLetter(i18n.t("ban"))}
</button>
) : (
<button
className={"d-flex align-self-start btn btn-secondary mr-2"}
onClick={linkEvent(this, this.handleModBanSubmit)}
aria-label={i18n.t("unban")}
>
{capitalizeFirstLetter(i18n.t("unban"))}
</button>
))}
</div> </div>
{pv.person.bio && ( {pv.person.bio && (
<div className="d-flex align-items-center mb-2"> <div className="d-flex align-items-center mb-2">
@ -476,6 +516,82 @@ export class Profile extends Component<any, ProfileState> {
); );
} }
banDialog() {
let pv = this.state.personRes?.person_view;
return (
<>
{this.state.showBanDialog && (
<form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
<div class="form-group row col-12">
<label class="col-form-label" htmlFor="profile-ban-reason">
{i18n.t("reason")}
</label>
<input
type="text"
id="profile-ban-reason"
class="form-control mr-2"
placeholder={i18n.t("reason")}
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
<label class="col-form-label" htmlFor={`mod-ban-expires`}>
{i18n.t("expires")}
</label>
<input
type="number"
id={`mod-ban-expires`}
class="form-control mr-2"
placeholder={i18n.t("number_of_days")}
value={this.state.banExpireDays}
onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
/>
<div class="form-group">
<div class="form-check">
<input
class="form-check-input"
id="mod-ban-remove-data"
type="checkbox"
checked={this.state.removeData}
onChange={linkEvent(this, this.handleModRemoveDataChange)}
/>
<label
class="form-check-label"
htmlFor="mod-ban-remove-data"
title={i18n.t("remove_content_more")}
>
{i18n.t("remove_content")}
</label>
</div>
</div>
</div>
{/* TODO hold off on expires until later */}
{/* <div class="form-group row"> */}
{/* <label class="col-form-label">Expires</label> */}
{/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* </div> */}
<div class="form-group row">
<button
type="cancel"
class="btn btn-secondary mr-2"
aria-label={i18n.t("cancel")}
onClick={linkEvent(this, this.handleModBanSubmitCancel)}
>
{i18n.t("cancel")}
</button>
<button
type="submit"
class="btn btn-secondary"
aria-label={i18n.t("ban")}
>
{i18n.t("ban")} {pv.person.name}
</button>
</div>
</form>
)}
</>
);
}
moderates() { moderates() {
return ( return (
<div> <div>
@ -534,6 +650,27 @@ export class Profile extends Component<any, ProfileState> {
this.fetchUserData(); this.fetchUserData();
} }
get canAdmin(): boolean {
return (
this.state.siteRes?.admins &&
canMod(
UserService.Instance.myUserInfo,
this.state.siteRes.admins.map(a => a.person.id),
this.state.personRes?.person_view.person.id
)
);
}
get personIsAdmin(): boolean {
return (
this.state.siteRes?.admins &&
isMod(
this.state.siteRes.admins.map(a => a.person.id),
this.state.personRes?.person_view.person.id
)
);
}
handlePageChange(page: number) { handlePageChange(page: number) {
this.updateUrl({ page }); this.updateUrl({ page });
} }
@ -549,6 +686,55 @@ export class Profile extends Component<any, ProfileState> {
}); });
} }
handleModBanShow(i: Profile) {
i.state.showBanDialog = true;
i.setState(i.state);
}
handleModBanReasonChange(i: Profile, event: any) {
i.state.banReason = event.target.value;
i.setState(i.state);
}
handleModBanExpireDaysChange(i: Profile, event: any) {
i.state.banExpireDays = event.target.value;
i.setState(i.state);
}
handleModRemoveDataChange(i: Profile, event: any) {
i.state.removeData = event.target.checked;
i.setState(i.state);
}
handleModBanSubmitCancel(i: Profile, event?: any) {
event.preventDefault();
i.state.showBanDialog = false;
i.setState(i.state);
}
handleModBanSubmit(i: Profile, event?: any) {
if (event) event.preventDefault();
let pv = i.state.personRes.person_view;
// If its an unban, restore all their data
let ban = !pv.person.banned;
if (ban == false) {
i.state.removeData = false;
}
let form: BanPerson = {
person_id: pv.person.id,
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: futureDaysToUnixTime(i.state.banExpireDays),
auth: authField(),
};
WebSocketService.Instance.send(wsClient.banPerson(form));
i.state.showBanDialog = false;
i.setState(i.state);
}
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
console.log(msg); console.log(msg);
@ -623,6 +809,11 @@ export class Profile extends Component<any, ProfileState> {
this.state.personRes.posts this.state.personRes.posts
.filter(c => c.creator.id == data.person_view.person.id) .filter(c => c.creator.id == data.person_view.person.id)
.forEach(c => (c.creator.banned = data.banned)); .forEach(c => (c.creator.banned = data.banned));
let pv = this.state.personRes.person_view;
if (pv.person.id == data.person_view.person.id) {
pv.person.banned = data.banned;
}
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.BlockPerson) { } else if (op == UserOperation.BlockPerson) {
let data = wsJsonToRes<BlockPersonResponse>(msg).data; let data = wsJsonToRes<BlockPersonResponse>(msg).data;

View file

@ -54,10 +54,10 @@ interface PostListingState {
showRemoveDialog: boolean; showRemoveDialog: boolean;
removeReason: string; removeReason: string;
showBanDialog: boolean; showBanDialog: boolean;
removeData: boolean;
banReason: string; banReason: string;
banExpireDays: number; banExpireDays: number;
banType: BanType; banType: BanType;
removeData: boolean;
showConfirmTransferSite: boolean; showConfirmTransferSite: boolean;
showConfirmTransferCommunity: boolean; showConfirmTransferCommunity: boolean;
imageExpanded: boolean; imageExpanded: boolean;
@ -91,10 +91,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
showRemoveDialog: false, showRemoveDialog: false,
removeReason: null, removeReason: null,
showBanDialog: false, showBanDialog: false,
removeData: false,
banReason: null, banReason: null,
banExpireDays: null, banExpireDays: null,
banType: BanType.Community, banType: BanType.Community,
removeData: false,
showConfirmTransferSite: false, showConfirmTransferSite: false,
showConfirmTransferCommunity: false, showConfirmTransferCommunity: false,
imageExpanded: false, imageExpanded: false,