Temp bans (#524)

* Updating translations.

* Adding temp bans.

* Using new lemmy-js-client with temp bans

* Fixing some lint and dep issues
This commit is contained in:
Dessalines 2022-01-09 12:53:11 -05:00 committed by GitHub
parent 9abe811021
commit 4915193ae5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1362 additions and 2006 deletions

@ -1 +1 @@
Subproject commit 1e0bb9920cda13bb128c87e85125b98ab8f319b6
Subproject commit 27a29ad5411438e4792e8e298aa5f4a3b60bb908

View file

@ -20,7 +20,7 @@
"@typescript-eslint/parser": "^5.6.0",
"autosize": "^5.0.1",
"check-password-strength": "^2.0.3",
"choices.js": "^9.0.1",
"choices.js": "^10.0.0",
"emoji-short-name": "^1.0.0",
"express": "~4.17.1",
"i18next": "^21.5.4",
@ -41,6 +41,7 @@
"moment": "^2.29.1",
"register-service-worker": "^1.7.2",
"rxjs": "^7.4.0",
"sass": "^1.47.0",
"serialize-javascript": "^6.0.0",
"tippy.js": "^6.3.7",
"toastify-js": "^1.11.2",
@ -51,12 +52,12 @@
"@babel/core": "^7.16.0",
"@babel/plugin-transform-runtime": "^7.16.4",
"@babel/plugin-transform-typescript": "^7.16.1",
"@babel/preset-env": "7.16.4",
"@babel/preset-env": "7.16.7",
"@babel/preset-typescript": "^7.16.0",
"@babel/runtime": "^7.16.3",
"@types/autosize": "^4.0.0",
"@types/express": "^4.17.13",
"@types/node": "^16.11.11",
"@types/node": "^17.0.8",
"@types/node-fetch": "^2.5.11",
"@types/serialize-javascript": "^5.0.1",
"@typescript-eslint/eslint-plugin": "^5.6.0",
@ -72,11 +73,10 @@
"husky": "^7.0.4",
"import-sort-style-module": "^6.0.0",
"iso-639-1": "^2.1.10",
"lemmy-js-client": "0.15.0-rc.6",
"lemmy-js-client": "0.15.0-rc.34",
"lint-staged": "^12.1.2",
"mini-css-extract-plugin": "^2.4.5",
"node-fetch": "^2.6.1",
"node-sass": "^7.0.0",
"prettier": "^2.5.1",
"prettier-plugin-import-sort": "^0.0.7",
"prettier-plugin-organize-imports": "^2.3.4",
@ -90,7 +90,7 @@
"typescript": "^4.5.2",
"webpack": "5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "4.6.0",
"webpack-dev-server": "4.7.2",
"webpack-node-externals": "^3.0.0"
},
"engines": {

View file

@ -28,7 +28,8 @@ import {
authField,
canMod,
colorList,
getUnixTime,
futureDaysToUnixTime,
isBanned,
isMod,
mdToHtml,
numToSI,
@ -51,7 +52,7 @@ interface CommentNodeState {
showBanDialog: boolean;
removeData: boolean;
banReason: string;
banExpires: string;
banExpireDays: number;
banType: BanType;
showConfirmTransferSite: boolean;
showConfirmTransferCommunity: boolean;
@ -96,7 +97,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
showBanDialog: false,
removeData: false,
banReason: null,
banExpires: null,
banExpireDays: null,
banType: BanType.Community,
collapsed: false,
viewSource: false,
@ -187,7 +188,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{i18n.t("bot_account").toLowerCase()}
</div>
)}
{(cv.creator_banned_from_community || cv.creator.banned) && (
{(cv.creator_banned_from_community || isBanned(cv.creator)) && (
<div className="badge badge-danger mr-2">
{i18n.t("banned")}
</div>
@ -614,7 +615,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.canAdmin && (
<>
{!this.isAdmin &&
(!cv.creator.banned ? (
(!isBanned(cv.creator) ? (
<button
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
@ -637,7 +638,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{i18n.t("unban_from_site")}
</button>
))}
{!cv.creator.banned &&
{!isBanned(cv.creator) &&
cv.creator.local &&
(!this.state.showConfirmAppointAsAdmin ? (
<button
@ -797,7 +798,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
{this.state.showBanDialog && (
<form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
<div class="form-group row">
<div class="form-group row col-12">
<label
class="col-form-label"
htmlFor={`mod-ban-reason-${cv.comment.id}`}
@ -812,6 +813,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
<label
class="col-form-label"
htmlFor={`mod-ban-expires-${cv.comment.id}`}
>
{i18n.t("expires")}
</label>
<input
type="number"
id={`mod-ban-expires-${cv.comment.id}`}
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
@ -1191,8 +1206,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
i.setState(i.state);
}
handleModBanExpiresChange(i: CommentNode, event: any) {
i.state.banExpires = event.target.value;
handleModBanExpireDaysChange(i: CommentNode, event: any) {
i.state.banExpireDays = event.target.value;
i.setState(i.state);
}
@ -1223,7 +1238,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
expires: futureDaysToUnixTime(i.state.banExpireDays),
auth: authField(),
};
WebSocketService.Instance.send(wsClient.banFromCommunity(form));
@ -1238,7 +1253,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
expires: futureDaysToUnixTime(i.state.banExpireDays),
auth: authField(),
};
WebSocketService.Instance.send(wsClient.banPerson(form));

View file

@ -1,9 +1,12 @@
import autosize from "autosize";
import { Component, linkEvent } from "inferno";
import {
BannedPersonsResponse,
GetBannedPersons,
GetSiteConfig,
GetSiteConfigResponse,
GetSiteResponse,
PersonViewSafe,
SaveSiteConfig,
SiteResponse,
UserOperation,
@ -34,6 +37,7 @@ interface AdminSettingsState {
siteConfigRes: GetSiteConfigResponse;
siteConfigForm: SaveSiteConfig;
loading: boolean;
banned: PersonViewSafe[];
siteConfigLoading: boolean;
}
@ -45,11 +49,12 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
siteRes: this.isoData.site_res,
siteConfigForm: {
config_hjson: null,
auth: authField(),
auth: null,
},
siteConfigRes: {
config_hjson: null,
},
banned: [],
loading: true,
siteConfigLoading: null,
};
@ -67,20 +72,34 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.state.siteConfigRes = this.isoData.routeData[0];
this.state.siteConfigForm.config_hjson =
this.state.siteConfigRes.config_hjson;
this.state.banned = this.isoData.routeData[1].banned;
this.state.siteConfigLoading = false;
this.state.loading = false;
} else {
this.state.siteConfigForm.auth = authField();
WebSocketService.Instance.send(
wsClient.getSiteConfig({
auth: authField(),
})
);
WebSocketService.Instance.send(
wsClient.getBannedPersons({
auth: authField(),
})
);
}
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let form: GetSiteConfig = { auth: req.auth };
return [req.client.getSiteConfig(form)];
let promises: Promise<any>[] = [];
let siteConfigForm: GetSiteConfig = { auth: req.auth };
promises.push(req.client.getSiteConfig(siteConfigForm));
let bannedPersonsForm: GetBannedPersons = { auth: req.auth };
promises.push(req.client.getBannedPersons(bannedPersonsForm));
return promises;
}
componentDidMount() {
@ -105,10 +124,6 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
render() {
return (
<div class="container">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? (
<h5>
<Spinner large />
@ -116,6 +131,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
) : (
<div class="row">
<div class="col-12 col-md-6">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.siteRes.site_view.site.id && (
<SiteForm site={this.state.siteRes.site_view.site} />
)}
@ -149,7 +168,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
<>
<h5>{i18n.t("banned_users")}</h5>
<ul class="list-unstyled">
{this.state.siteRes.banned.map(banned => (
{this.state.banned.map(banned => (
<li class="list-inline-item">
<PersonListing person={banned.person} />
</li>
@ -225,6 +244,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.state.siteRes.site_view = data.site_view;
this.setState(this.state);
toast(i18n.t("site_saved"));
} else if (op == UserOperation.GetBannedPersons) {
let data = wsJsonToRes<BannedPersonsResponse>(msg).data;
this.state.banned = data.banned;
this.setState(this.state);
} else if (op == UserOperation.GetSiteConfig) {
let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
this.state.siteConfigRes = data;

View file

@ -896,19 +896,6 @@ export class Home extends Component<any, HomeState> {
this.setState(this.state);
} else if (op == UserOperation.BanPerson) {
let data = wsJsonToRes<BanPersonResponse>(msg).data;
let found = this.state.siteRes.banned.find(
p => (p.person.id = data.person_view.person.id)
);
// Remove the banned if its found in the list, and the action is an unban
if (found && !data.banned) {
this.state.siteRes.banned = this.state.siteRes.banned.filter(
i => i.person.id !== data.person_view.person.id
);
} else {
this.state.siteRes.banned.push(data.person_view);
}
this.state.posts
.filter(p => p.creator.id == data.person_view.person.id)
.forEach(p => (p.creator.banned = data.banned));

View file

@ -26,8 +26,9 @@ import { UserService, WebSocketService } from "../../services";
import {
authField,
canMod,
getUnixTime,
futureDaysToUnixTime,
hostname,
isBanned,
isImage,
isMod,
isVideo,
@ -54,7 +55,7 @@ interface PostListingState {
showBanDialog: boolean;
removeData: boolean;
banReason: string;
banExpires: string;
banExpireDays: number;
banType: BanType;
showConfirmTransferSite: boolean;
showConfirmTransferCommunity: boolean;
@ -90,7 +91,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
showBanDialog: false,
removeData: false,
banReason: null,
banExpires: null,
banExpireDays: null,
banType: BanType.Community,
showConfirmTransferSite: false,
showConfirmTransferCommunity: false,
@ -294,7 +295,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</span>
)}
{(post_view.creator_banned_from_community ||
post_view.creator.banned) && (
isBanned(post_view.creator)) && (
<span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
)}
{post_view.creator_blocked && (
@ -900,7 +901,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{this.canAdmin && (
<>
{!this.isAdmin &&
(!post_view.creator.banned ? (
(!isBanned(post_view.creator) ? (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModBanShow)}
@ -917,7 +918,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{i18n.t("unban_from_site")}
</button>
))}
{!post_view.creator.banned && post_view.creator.local && (
{!isBanned(post_view.creator) && post_view.creator.local && (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleAddAdmin)}
@ -1013,7 +1014,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)}
{this.state.showBanDialog && (
<form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
<div class="form-group row">
<div class="form-group row col-12">
<label class="col-form-label" htmlFor="post-listing-ban-reason">
{i18n.t("reason")}
</label>
@ -1025,6 +1026,17 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
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
@ -1496,8 +1508,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
i.setState(i.state);
}
handleModBanExpiresChange(i: PostListing, event: any) {
i.state.banExpires = event.target.value;
handleModBanExpireDaysChange(i: PostListing, event: any) {
i.state.banExpireDays = event.target.value;
i.setState(i.state);
}
@ -1528,7 +1540,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
expires: futureDaysToUnixTime(i.state.banExpireDays),
auth: authField(),
};
WebSocketService.Instance.send(wsClient.banFromCommunity(form));
@ -1543,7 +1555,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
expires: futureDaysToUnixTime(i.state.banExpireDays),
auth: authField(),
};
WebSocketService.Instance.send(wsClient.banPerson(form));

View file

@ -14,6 +14,7 @@ import {
ListingType,
MyUserInfo,
PersonBlockView,
PersonSafe,
PersonViewSafe,
PostReportView,
PostView,
@ -285,6 +286,14 @@ export function getUnixTime(text: string): number {
return text ? new Date(text).getTime() / 1000 : undefined;
}
export function futureDaysToUnixTime(days: number): number {
return days
? Math.trunc(
new Date(Date.now() + 1000 * 60 * 60 * 24 * days).getTime() / 1000
)
: undefined;
}
export function canMod(
myUserInfo: MyUserInfo,
modIds: number[],
@ -1517,3 +1526,16 @@ const SHORTNUM_SI_FORMAT = new Intl.NumberFormat("en-US", {
export function numToSI(value: number): string {
return SHORTNUM_SI_FORMAT.format(value);
}
export function isBanned(ps: PersonSafe): boolean {
// Add Z to convert from UTC date
if (ps.ban_expires) {
if (ps.banned && new Date(ps.ban_expires + "Z") > new Date()) {
return true;
} else {
return false;
}
} else {
return ps.banned;
}
}

3209
yarn.lock

File diff suppressed because it is too large Load diff