Page to list unapproved w2l templates

This commit is contained in:
Brandon Thomas committed 2021-09-12 01:37:23 -04:00
1 parent 4116ea8425
commit 8d94167bc5
6 files changed
+228

No files matched your search

+4
View File
@@ -266,6 +266,10 @@ class ApiConfig {
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/jobs/w2l_inference_queue_stats`;
}
getModerationPendingW2lTemplates(): string {
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/pending/w2l_templates`;
}
private getScheme() : string {
return this.isLocalDev ? "http" : "https";
}
@@ -0,0 +1,77 @@
import { ApiConfig } from "../../../common/ApiConfig";
export interface PendingW2lTemplates {
success: boolean,
templates: Array<PendingW2lTemplatesEntryForList>
}
export interface PendingW2lTemplatesEntryForList {
template_token: string,
title: string,
template_type: string,
duration_millis: number,
frame_width: number,
frame_height: number,
creator_user_token: string,
creator_username: string,
creator_display_name: string,
creator_gravatar_hash: string,
created_at: Date,
}
export enum PendingW2lTemplatesLookupError {
NotAuthorized,
ServerError,
FrontendError,
}
export type GetPendingW2lTemplatesResponse = PendingW2lTemplates | PendingW2lTemplatesLookupError;
export function GetPendingW2lTemplatesIsOk(response: GetPendingW2lTemplatesResponse): response is PendingW2lTemplates {
return response.hasOwnProperty('templates');
}
export function GetPendingW2lTemplatesIsErr(response: GetPendingW2lTemplatesResponse): response is PendingW2lTemplatesLookupError {
return !response.hasOwnProperty('templates');
}
interface PendingW2lTemplatesResponsePayload {
success: boolean,
error_reason?: string,
templates?: PendingW2lTemplates,
}
export async function GetPendingW2lTemplates() : Promise<GetPendingW2lTemplatesResponse>
{
const endpoint = new ApiConfig().getModerationPendingW2lTemplates();
return await fetch(endpoint, {
method: 'GET',
headers: {
'Accept': 'application/json',
},
credentials: 'include',
})
.then(res => res.json())
.then(res => {
const response : PendingW2lTemplatesResponsePayload = res;
if (response?.success) {
return res as PendingW2lTemplates; // TODO: This is not the way.
}
if (response?.success === false) {
if (response.error_reason?.includes("authorized")) {
return PendingW2lTemplatesLookupError.NotAuthorized;
} else {
return PendingW2lTemplatesLookupError.ServerError;
}
}
return PendingW2lTemplatesLookupError.FrontendError;
})
.catch(e => {
return PendingW2lTemplatesLookupError.FrontendError;
});
}
@@ -40,6 +40,7 @@ import { ProfileBanFc } from './profile/profile_ban/ProfileBanFc';
import { ModerationUserListFc } from './moderation/moderation_user_list/ModerationUserList';
import { LeaderboardFc } from './leaderboard/LeaderboardFc';
import { ModerationJobStatsFc } from './moderation/moderation_job_stats/ModerationJobStatsFc';
import { ModerationPendingW2lTemplatesFc } from './moderation/moderation_pending_w2l_templates/ModerationPendingW2lTemplatesFc';
interface Props {
sessionWrapper: SessionWrapper,
@@ -285,6 +286,12 @@ class NewVocodesContainer extends React.Component<Props, State> {
/>
</Route>
<Route path="/moderation/approve/w2l_templates">
<ModerationPendingW2lTemplatesFc
sessionWrapper={this.props.sessionWrapper}
/>
</Route>
<Route path="/moderation">
<ModerationFc
sessionWrapper={this.props.sessionWrapper}
@@ -0,0 +1,15 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPhotoVideo } from '@fortawesome/free-solid-svg-icons';
interface Props {
title?: string,
}
export function PhotoVideoIcon(props: Props) {
const title = props.title === undefined ? 'Media' : props.title;
return (
<FontAwesomeIcon icon={faPhotoVideo} title={title} />
);
}
@@ -37,6 +37,13 @@ function ModerationFc(props: Props) {
<br />
<Link
to="/moderation/approve/w2l_templates"
className="button is-link is-large is-fullwidth is-light"
>Unapproved W2L Templates</Link>
<br />
<p>
More mod controls will be added in the future: user roles, activity tracking,
timed bans, account bans, etc.
@@ -0,0 +1,118 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { SessionWrapper } from '../../../../session/SessionWrapper';
import { formatDistance } from 'date-fns';
import { FrontendUrlConfig } from '../../../../common/FrontendUrlConfig';
import { GravatarFc } from '../../_common/GravatarFc';
import { BackLink } from '../../_common/BackLink';
import { GetPendingW2lTemplates, GetPendingW2lTemplatesIsOk, PendingW2lTemplatesEntryForList } from '../../../api/moderation/GetPendingW2lTemplates';
import { PhotoVideoIcon } from '../../_icons/PhotoVideoIcon';
interface Props {
sessionWrapper: SessionWrapper,
}
function ModerationPendingW2lTemplatesFc(props: Props) {
const [templates, setTemplates] = useState<Array<PendingW2lTemplatesEntryForList>>([]);
const getUsers = useCallback(async () => {
const response = await GetPendingW2lTemplates();
if (GetPendingW2lTemplatesIsOk(response)) {
setTemplates(response.templates);
}
}, []);
useEffect(() => {
getUsers();
}, [getUsers]);
if (!templates) {
return <div />
}
if (!props.sessionWrapper.canApproveW2lTemplates()) {
return <h1>Unauthorized</h1>;
}
const now = new Date();
let rows : Array<JSX.Element> = [];
templates.forEach(template=> {
const createTime = new Date(template.created_at);
const relativeCreateTime = formatDistance(createTime, now, { addSuffix: true });
rows.push(
<tr key={template.template_token}>
<td>
<Link to={FrontendUrlConfig.w2lTemplatePage(template.template_token)}>
<PhotoVideoIcon title="W2l Template" />
&nbsp;
{template.title}
</Link>
</td>
<td>
<Link to={FrontendUrlConfig.userProfilePage(template.creator_display_name)}>
<GravatarFc username={template.creator_display_name} email_hash={template.creator_gravatar_hash} size={12} />
&nbsp;
{template.creator_display_name}
</Link>
</td>
<td>{template.template_type}</td>
<td>{relativeCreateTime}</td>
</tr>
)
});
return (
<div>
<h1 className="title is-1"> Unapproved W2L Templates </h1>
<BackLink link={FrontendUrlConfig.moderationMain()} text="Back to moderation" />
<br />
<br />
<p>
This lists the templates that haven't yet been approved for display.
</p>
<br />
<p>
Don't delete templates unless they overwhelmingly break the rules.
Users can use templates in private without them necessarily being approved for public use.
</p>
<br />
<p>
Setting approved = TRUE will show the template on the main site for everyone to use.
Setting approved = FALSE will still let the author and people directly accessing via
URL to use the template, but will not make it public.
It will also remove it from the moderation queue.
</p>
<br />
<table className="table is-fullwidth">
<thead>
<tr>
<th>Template</th>
<th>Creator</th>
<th>Type</th>
<th>Created At</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
)
}
export { ModerationPendingW2lTemplatesFc };