Skip to content

Commit

Permalink
Merge pull request online-go#2586 from GreenAsJade/moderator_pref_to_…
Browse files Browse the repository at this point in the history
…control_report_quota

Moderator pref to control report quota
  • Loading branch information
anoek authored Feb 18, 2024
2 parents 69aeed5 + 40daf93 commit 866b152
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 52 deletions.
17 changes: 7 additions & 10 deletions src/components/IncidentReportTracker/IncidentReportTracker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { ignore, errorAlerter } from "misc";
import { openReportedConversationModal } from "ReportedConversationModal";
import { AutoTranslate } from "AutoTranslate";
import { report_categories } from "Report";
import { Report, report_manager, DAILY_REPORT_GOAL } from "report_manager";
import { Report, report_manager } from "report_manager";
import { useRefresh, useUser } from "hooks";
import * as DynamicHelp from "react-dynamic-help";

Expand All @@ -39,6 +39,7 @@ export function IncidentReportTracker(): JSX.Element | null {
const [show_incident_list, setShowIncidentList] = React.useState(false);
const [normal_ct, setNormalCt] = React.useState(0);
const [prefer_hidden] = usePreference("hide-incident-reports");
const [report_quota] = usePreference("moderator.report-quota");
const refresh = useRefresh();

const { registerTargetItem, triggerFlow, signalUsed } = React.useContext(DynamicHelp.Api);
Expand Down Expand Up @@ -151,16 +152,16 @@ export function IncidentReportTracker(): JSX.Element | null {
return;
}

if (user.is_moderator || user.moderator_powers > 0) {
if ((user.is_moderator || user.moderator_powers > 0) && !!report_quota) {
const handled_today = user.reports_handled_today || 0;
setNormalCt(Math.max(0, Math.min(count, DAILY_REPORT_GOAL - handled_today)));
setNormalCt(Math.max(0, Math.min(count, report_quota - handled_today)));
} else {
setNormalCt(count);
}
}

function updateUser() {
updateCt(report_manager.getAvailableReports().length);
updateCt(report_manager.getEligibleReports().length);
}

data.watch("user", updateUser);
Expand All @@ -186,7 +187,7 @@ export function IncidentReportTracker(): JSX.Element | null {
return null;
}

const reports = report_manager.getAvailableReports();
const reports = report_manager.getEligibleReports();
const hide_indicator = (reports.length === 0 && !user.is_moderator) || prefer_hidden;

function getReportType(report: Report): string {
Expand Down Expand Up @@ -221,11 +222,7 @@ export function IncidentReportTracker(): JSX.Element | null {
className={`fa fa-exclamation-triangle ${normal_ct > 0 ? "active" : ""}`}
ref={incident_report_indicator}
/>
{user.is_moderator && (
<span className={`count ${normal_ct > 0 ? "active" : ""}`}>
{normal_ct}
</span>
)}
<span className={`count ${normal_ct > 0 ? "active" : ""}`}>{normal_ct}</span>
</div>
)}
{show_incident_list && (
Expand Down
1 change: 1 addition & 0 deletions src/lib/preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export const defaults = {
"moderator.join-games-anonymously": true,
"moderator.hide-flags": false,
"moderator.hide-profile-information": false, // hide extra moderator information
"moderator.report-quota": 10,
"moderator.report-settings": {} as {
[category: string]: {
priority: number;
Expand Down
17 changes: 12 additions & 5 deletions src/lib/report_manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ import { browserHistory } from "ogsHistory";
import { get, post } from "requests";
import { MODERATOR_POWERS } from "moderation";

export const DAILY_REPORT_GOAL = 10;

const DONT_OFFER_COMMUNITY_MODERATION_TYPES_TO_MODERATORS = false;

interface Vote {
Expand Down Expand Up @@ -204,7 +202,15 @@ class ReportManager extends EventEmitter<Events> {
this.emit("update");
}

public getAvailableReports(): Report[] {
public getEligibleReports(): Report[] {
const quota = preferences.get("moderator.report-quota");
return !quota || this.getHandledTodayCount() < preferences.get("moderator.report-quota")
? this.getAvailableReports()
: [];
}

// Clients should use getEligibleReports
private getAvailableReports(): Report[] {
const user = data.get("user");

return this.sorted_active_incident_reports.filter((report) => {
Expand All @@ -226,7 +232,7 @@ class ReportManager extends EventEmitter<Events> {
}

// Community moderators only get to see reports that they have the power for and
// that they have not yet voted on.
// that they have not yet voted on, and are not escalated
const has_handle_score_cheat =
(user.moderator_powers & MODERATOR_POWERS.HANDLE_SCORE_CHEAT) > 0;
const has_handle_escaping =
Expand Down Expand Up @@ -423,9 +429,10 @@ class ReportManager extends EventEmitter<Events> {
return data.get("user").reports_handled_today || 0;
}
public getReportsLeftUntilGoal(): number {
const report_quota = preferences.get("moderator.report-quota");
const count = this.getAvailableReports().length;
const handled_today = this.getHandledTodayCount();
return Math.max(0, Math.min(count, DAILY_REPORT_GOAL - handled_today));
return Math.max(0, Math.min(count, report_quota - handled_today));
}
}

Expand Down
21 changes: 12 additions & 9 deletions src/views/ReportsCenter/ReportsCenter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import * as React from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useUser, useRefresh } from "hooks";
import { report_categories, ReportDescription } from "Report";
import { report_manager, DAILY_REPORT_GOAL } from "report_manager";
import { report_manager } from "report_manager";
import Select from "react-select";
import { _ } from "translate";
import { ViewReport } from "./ViewReport";
import { ReportsCenterSettings } from "./ReportsCenterSettings";
import { ReportsCenterHistory } from "./ReportsCenterHistory";
import { MOD_POWER_NEEDED } from "moderation";
import { usePreference } from "preferences";

interface OtherView {
special: string;
Expand Down Expand Up @@ -66,7 +67,10 @@ export function ReportsCenter(): JSX.Element | null {
const report_id = parseInt(params["report_id"] || "0");
const category = params["category"] || "all";

const reports = report_manager.getAvailableReports();
const [report_quota] = usePreference("moderator.report-quota");

const reports = report_manager.getEligibleReports();

const counts: any = {};
for (const report of reports) {
counts[report.report_type] = (counts[report.report_type] || 0) + 1;
Expand All @@ -89,7 +93,7 @@ export function ReportsCenter(): JSX.Element | null {

const setToFirstAvailableReport = () => {
if (!report_id) {
const reports = report_manager.getAvailableReports();
const reports = report_manager.getEligibleReports();

if (reports.length) {
for (let i = 0; i < reports.length; ++i) {
Expand Down Expand Up @@ -146,7 +150,7 @@ export function ReportsCenter(): JSX.Element | null {
{_("Reports Center")}
</h2>

{user.is_moderator && (
{!!report_quota && (
<div className="progress" style={{ minWidth: "10rem" }}>
<div
className="progress-bar primary"
Expand All @@ -155,10 +159,10 @@ export function ReportsCenter(): JSX.Element | null {
report_manager.getReportsLeftUntilGoal() <= 0
? 100
: (Math.min(
DAILY_REPORT_GOAL,
report_quota,
report_manager.getHandledTodayCount(),
) /
DAILY_REPORT_GOAL) *
report_quota) *
100
}%`,
}}
Expand All @@ -173,13 +177,12 @@ export function ReportsCenter(): JSX.Element | null {
className="progress-bar empty"
style={{
width: `${
(report_manager.getReportsLeftUntilGoal() / DAILY_REPORT_GOAL) *
100
(report_manager.getReportsLeftUntilGoal() / report_quota) * 100
}%`,
}}
>
{report_manager.getHandledTodayCount() === 0
? "Daily report goal: " + DAILY_REPORT_GOAL
? "Daily report goal: " + report_quota
: ""}
</div>
)}
Expand Down
89 changes: 62 additions & 27 deletions src/views/Settings/ModeratorPreferences.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { usePreference } from "preferences";
import { Toggle } from "Toggle";
import { SettingGroupPageProps, PreferenceLine } from "SettingsCommon";
import { ReportsCenterSettings } from "ReportsCenter";
import * as preferences from "preferences";

export function ModeratorPreferences(_props: SettingGroupPageProps): JSX.Element | null {
const [incident_report_notifications, setIncidentReportNotifications] = usePreference(
Expand All @@ -38,42 +39,76 @@ export function ModeratorPreferences(_props: SettingGroupPageProps): JSX.Element
"moderator.hide-player-card-mod-controls",
);

const [report_quota, _setReportQuota] = React.useState(
preferences.get("moderator.report-quota"),
);

const user = data.get("user");

if (!user.is_moderator) {
function updateReportQuota(ev: React.ChangeEvent<HTMLInputElement>) {
let quota = parseInt(ev.target.value);
if (!isNaN(quota)) {
quota = Math.min(200, Math.max(0, quota));
preferences.set("moderator.report-quota", quota);
_setReportQuota(quota);
} else {
_setReportQuota(ev.target.value as any);
}
}
if (!user.is_moderator && !user.moderator_powers) {
return null;
}

return (
<div>
<PreferenceLine title={_("Notify me when an incident is submitted for moderation")}>
<Toggle
checked={incident_report_notifications}
onChange={setIncidentReportNotifications}
<PreferenceLine title={_("Report quota")} description={_("Set to 0 for no quota.")}>
<input
value={report_quota}
onChange={updateReportQuota}
type="number"
min="0"
max="100"
step="1"
/>
</PreferenceLine>
<PreferenceLine title="Hide incident reports">
<Toggle checked={hide_incident_reports} onChange={setHideIncidentReports} />
</PreferenceLine>
<PreferenceLine title="Hide claimed reports">
<Toggle checked={hide_claimed_reports} onChange={setHideClaimedReports} />
</PreferenceLine>
<PreferenceLine title="Join games anonymously">
<Toggle checked={join_games_anonymously} onChange={setJoinGamesAnonymously} />
</PreferenceLine>
<PreferenceLine title="Hide flags">
<Toggle checked={hide_flags} onChange={setHideFlags} />
</PreferenceLine>
<PreferenceLine title="Hide moderator information on profile pages">
<Toggle checked={hide_profile} onChange={setHideProfile} />
</PreferenceLine>
<PreferenceLine title="Hide moderator controls on player cards">
<Toggle
checked={hide_player_card_mod_controls}
onChange={setHidePlayerCardModControls}
/>
</PreferenceLine>
<ReportsCenterSettings />
{user.is_moderator && (
<>
<PreferenceLine
title={_("Notify me when an incident is submitted for moderation")}
>
<Toggle
checked={incident_report_notifications}
onChange={setIncidentReportNotifications}
/>
</PreferenceLine>
<PreferenceLine title="Hide incident reports">
<Toggle checked={hide_incident_reports} onChange={setHideIncidentReports} />
</PreferenceLine>
<PreferenceLine title="Hide claimed reports">
<Toggle checked={hide_claimed_reports} onChange={setHideClaimedReports} />
</PreferenceLine>
<PreferenceLine title="Join games anonymously">
<Toggle
checked={join_games_anonymously}
onChange={setJoinGamesAnonymously}
/>
</PreferenceLine>
<PreferenceLine title="Hide flags">
<Toggle checked={hide_flags} onChange={setHideFlags} />
</PreferenceLine>
<PreferenceLine title="Hide moderator information on profile pages">
<Toggle checked={hide_profile} onChange={setHideProfile} />
</PreferenceLine>
<PreferenceLine title="Hide moderator controls on player cards">
<Toggle
checked={hide_player_card_mod_controls}
onChange={setHidePlayerCardModControls}
/>
</PreferenceLine>

<ReportsCenterSettings />
</>
)}
</div>
);
}
5 changes: 4 additions & 1 deletion src/views/Settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,10 @@ export function Settings(): JSX.Element {
<div id="SettingsContainer">
<SettingsGroupSelector>
{groups
.filter((x) => x.key !== "moderator" || user.is_moderator)
.filter(
(x) =>
x.key !== "moderator" || user.is_moderator || user.moderator_powers,
)
.map((x) => (
<SettingsGroup
key={x.key}
Expand Down

0 comments on commit 866b152

Please sign in to comment.