list and add IP address bans

This commit is contained in:
Brandon Thomas committed 2021-06-14 02:38:48 -04:00
1 parent 18b8569292
commit cbd8303e88
5 files changed
+257 -1

No files matched your search

+12
View File
@@ -198,6 +198,18 @@ class ApiConfig {
return `${this.getScheme()}://${this.getNewApiHost()}/events`;
}
getModerationIpBanList(): string {
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/ip_bans/list`;
}
createModerationIpBan(): string {
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/ip_bans/add`;
}
deleteModerationIpBan(ipAddress: string): string {
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/ip_bans/${ipAddress}/delete`;
}
private getScheme() : string {
return this.isLocalDev ? "http" : "https";
}
+10
View File
@@ -7,9 +7,19 @@ interface Props {
}
function NewFooterNavFc(props: Props) {
let moderationLink = <span />;
if (props.sessionWrapper.canBanUsers()) {
moderationLink = (
<Link to="/moderation">Mod Controls</Link>
);
}
return (
<div>
<hr />
{moderationLink}
<p>
We're trying to build a democratized <a href="https://the.storyteller.company">future of creativity, filmmaking and storytelling</a>.
Contact <Link to="/profile/echelon">@echelon</Link> for more information.
+14 -1
View File
@@ -1,6 +1,8 @@
import React from 'react';
import { FirehoseEventListFc } from './firehose/FirehoseEventListFc';
import { LoginFc } from './login/LoginFc';
import { ModerationFc } from './moderation/ModerationFc';
import { ModerationIpBanListFc } from './moderation_ip_ban_list/ModerationIpBanListFc';
import { NewFooterNavFc } from './NewFooterNavFc';
import { NewTopNavFc } from './NewTopNavFc';
import { ProfileEditFc } from './profile_edit/ProfileEditFc';
@@ -15,7 +17,6 @@ import { TtsModelUploadJob } from '../jobs/TtsModelUploadJobs';
import { TtsModelViewFc } from './tts_model_view/TtsModelViewFc';
import { TtsResultViewFc } from './tts_result_view/TtsResultViewFc';
import { UploadChoiceFc } from './upload/UploadChoiceFc';
import { UploadComponent } from './upload/UploadComponent';
import { UploadTtsModelFc } from './upload/UploadTtsModelFc';
import { UploadW2lPhotoFc } from './upload/UploadW2lPhotoFc';
import { UploadW2lVideoFc } from './upload/UploadW2lVideoFc';
@@ -176,6 +177,18 @@ class NewVocodesContainer extends React.Component<Props, State> {
/>
</Route>
<Route path="/moderation/ip_bans">
<ModerationIpBanListFc
sessionWrapper={this.props.sessionWrapper}
/>
</Route>
<Route path="/moderation">
<ModerationFc
sessionWrapper={this.props.sessionWrapper}
/>
</Route>
<Route path="/">
<TtsModelFormFc
sessionWrapper={this.props.sessionWrapper}
@@ -0,0 +1,32 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { SessionWrapper } from '../../session/SessionWrapper';
interface Props {
sessionWrapper: SessionWrapper,
}
function ModerationFc(props: Props) {
if (!props.sessionWrapper.canBanUsers()) {
return <h1>Unauthorized</h1>;
}
return (
<div>
<h1 className="title is-1"> Moderation Controls </h1>
<Link
to="/moderation/ip_bans"
className="button is-link is-large is-fullwidth is-outlined"
>IP Ban List</Link>
<br />
<p>More mod controls will be added in the future: user roles, activity tracking, timed bans, account bans, etc.</p>
</div>
)
}
export { ModerationFc };
@@ -0,0 +1,189 @@
import React, { useEffect, useState } from 'react';
import { ApiConfig } from '../../common/ApiConfig';
import { SessionWrapper } from '../../session/SessionWrapper';
interface Props {
sessionWrapper: SessionWrapper,
}
interface IpBanListResponse {
success: boolean,
ip_address_bans: Array<IpBanListItem>,
}
interface IpBanListItem {
ip_address: string,
maybe_target_user_token: string,
maybe_target_username: string,
mod_user_token: string,
mod_notes: string,
created_at: string,
updated_at: string,
}
function ModerationIpBanListFc(props: Props) {
const [ipBanList, setIpBanList] = useState<Array<IpBanListItem>>([]);
// Form
const [newIpAddress, setNewIpAddress] = useState<string>("");
const [modNotes, setModNotes] = useState<string>("");
useEffect(() => {
const api = new ApiConfig();
const endpointUrl = api.getModerationIpBanList();
fetch(endpointUrl, {
method: 'GET',
headers: {
'Accept': 'application/json',
},
credentials: 'include',
})
.then(res => res.json())
.then(res => {
const response : IpBanListResponse = res;
if (!response.success) {
return;
}
setIpBanList(response.ip_address_bans)
})
.catch(e => {
//this.props.onSpeakErrorCallback();
});
}, []); // NB: Empty array dependency sets to run ONLY on mount
const handleNewIpAddressChange = (ev: React.FormEvent<HTMLInputElement>) => {
setNewIpAddress((ev.target as HTMLInputElement).value)
};
const handleModNotesChange = (ev: React.FormEvent<HTMLInputElement>) => {
setModNotes((ev.target as HTMLInputElement).value)
};
const handleFormSubmit = (ev: React.FormEvent<HTMLFormElement>) : boolean => {
ev.preventDefault();
const api = new ApiConfig();
const endpointUrl = api.createModerationIpBan();
const request = {
ip_address: newIpAddress,
mod_notes: modNotes,
}
fetch(endpointUrl, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify(request),
})
.then(res => res.json())
.then(res => {
if (res.success) {
history.go(0); // NB: Force reload
}
})
.catch(e => {});
return false;
}
if (!props.sessionWrapper.canBanUsers()) {
return <h1>Unauthorized</h1>;
}
let rows : Array<JSX.Element> = [];
ipBanList.forEach(ban => {
rows.push(
<tr key={ban.ip_address}>
<td>{ban.ip_address}</td>
<td>{ban.mod_notes}</td>
<td>{ban.created_at}</td>
</tr>
)
});
return (
<div>
<h1 className="title is-1"> Moderation Ip Ban List </h1>
<p>IP Address bans will prevent bad actors from using and abusing the website.</p>
<br />
<h3 className="title is-3"> Create Ban </h3>
<form onSubmit={handleFormSubmit}>
<div className="field">
<label className="label">Ip Address</label>
<div className="control has-icons-left has-icons-right">
<input
onChange={handleNewIpAddressChange}
className="input"
type="text"
placeholder="IP Address, eg. 255.255.255.255"
value={newIpAddress}
/>
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
<span className="icon is-small is-right">
<i className="fas fa-exclamation-triangle"></i>
</span>
</div>
{/*<p className="help">{invalidReason}</p>*/}
</div>
<div className="field">
<label className="label">Moderator Notes</label>
<div className="control has-icons-left has-icons-right">
<input
onChange={handleModNotesChange}
className="input"
type="text"
placeholder="Notes / reason for ban"
value={modNotes}
/>
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
<span className="icon is-small is-right">
<i className="fas fa-exclamation-triangle"></i>
</span>
</div>
{/*<p className="help">{invalidReason}</p>*/}
</div>
<button className="button is-danger is-large is-fullwidth">Create Ban</button>
</form>
<br />
<br />
<h3 className="title is-3"> Existing Bans </h3>
<table className="table">
<thead>
<tr>
<th>IP Address</th>
<th>Moderator Notes</th>
<th>Created At</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
)
}
export { ModerationIpBanListFc };