Skip to content

Commit c3fb9ce

Browse files
authored
feat(mod): CheckFlag converted into admin-only UI element (#2564)
May or may not become a toggle for blacklisting/whitelisting people later, still thinking of ways to fix our flagged user issue
1 parent 69a8cc0 commit c3fb9ce

File tree

7 files changed

+108
-110
lines changed

7 files changed

+108
-110
lines changed

data/constants.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,6 @@ module.exports = {
439439
forceSignOut: true,
440440
viewIPs: true,
441441
viewAlts: true,
442-
viewFlagged: true,
443442
clearSetupName: true,
444443
clearUserContent: true,
445444
clearFamilyContent: true,
@@ -517,7 +516,6 @@ module.exports = {
517516
"disableAllCensors",
518517
"kick",
519518
"announce",
520-
"viewFlagged",
521519
"approvePending",
522520
"changeUsersName",
523521
"reviewPrivate",
@@ -582,7 +580,6 @@ module.exports = {
582580
"disableAllCensors",
583581
"kick",
584582
"announce",
585-
"viewFlagged",
586583
"approvePending",
587584
"reviewPrivate",
588585
"approveRanked",

data/violations.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const violationDefinitions = [
1919
id: "intolerance",
2020
name: "Intolerance",
2121
description:
22-
"Any disrespectful behavior on the basis of group identity. Includes bigotry of any kind (racism, homophobia, transphobia, misogyny, etc.), bypassing slur filters, and genocide denial.",
22+
"Any disrespectful behavior on the basis of group identity. Includes bigotry of any kind (racism, homophobia, transphobia, misogyny, etc.), bypassing slur filters, and genocide denial. Please note that one is not permitted to use slurs or bigoted phrases despite belonging to affected groups (i.e. reclamation).",
2323
offenses: [
2424
"1 day",
2525
"3 days",
@@ -35,7 +35,7 @@ const violationDefinitions = [
3535
id: "adult-content",
3636
name: "Adult Content",
3737
description:
38-
'Graphic descriptions of adult behavior, including explicit sex acts, drug use, or descriptions of real violence. Restrict to a "13 and up" mindset.',
38+
"Graphic or textual descriptions of adult behavior, including explicit sex acts, drug use, mentions of sites/content intended to shock or disturb, pornographic websites, or descriptions of real violence.",
3939
offenses: [
4040
"1 day",
4141
"3 days",

react_main/src/pages/Policy/Moderation/commands.js

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -590,28 +590,6 @@ export function useModCommands(argValues, commandRan, setResults) {
590590
.catch(errorAlert);
591591
},
592592
},
593-
"Check Flagged": {
594-
perm: "viewFlagged",
595-
category: "User Management",
596-
args: [
597-
{
598-
label: "User",
599-
name: "userId",
600-
type: "user_search",
601-
},
602-
],
603-
run: function () {
604-
axios
605-
.get(`/api/mod/flagged?userId=${argValues.userId}`)
606-
.then((res) => {
607-
if (res.data) alert("Flagged!");
608-
else alert("Not flagged");
609-
610-
commandRan();
611-
})
612-
.catch(errorAlert);
613-
},
614-
},
615593
"Clear Setup Name": {
616594
perm: "clearSetupName",
617595
category: "Setup Management",

react_main/src/pages/Policy/Rules.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default function Rules() {
5555
UltiMafia Rules of Conduct
5656
</Typography>
5757
<Typography variant="body2" color="text.secondary" paragraph>
58-
Last Updated: February 6, 2026
58+
Last Updated: February 12, 2026
5959
</Typography>
6060

6161
<Box sx={{ borderBottom: 1, borderColor: "divider"}}>

react_main/src/pages/User/Profile.jsx

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export default function Profile() {
115115
const [nameHistory, setNameHistory] = useState([]);
116116
const [nameHistoryLoading, setNameHistoryLoading] = useState(false);
117117
const [joined, setJoined] = useState(null);
118+
const [isFlagged, setIsFlagged] = useState(false);
118119

119120
const user = useContext(UserContext);
120121
const siteInfo = useContext(SiteInfoContext);
@@ -127,6 +128,7 @@ export default function Profile() {
127128
const isSelf = profileUserId === user.id;
128129
const isBlocked = !isSelf && user.blockedUsers.indexOf(profileUserId) !== -1;
129130
const canViewNameHistory = user.perms.seeModPanel;
131+
const canViewFlagged = user.perms.viewFlagged;
130132

131133
// userId is the id of the current profile
132134
// user.id is the id of the current user
@@ -200,6 +202,7 @@ export default function Profile() {
200202
setEditingPronouns(false);
201203
setUserFamily(null);
202204
setProfileFamily(null);
205+
setIsFlagged(false);
203206

204207
if (userId) {
205208
setProfileLoaded(false);
@@ -252,6 +255,7 @@ export default function Profile() {
252255
setTrophies(res.data.trophies || []);
253256
setProfileFamily(res.data.family || null);
254257
setJoined(res.data.joined || null);
258+
setIsFlagged(Boolean(res.data.flagged));
255259
setFriendsPage(1);
256260
loadFriends(resolvedId, "", 1);
257261

@@ -888,60 +892,77 @@ export default function Profile() {
888892
justifyContent: "center",
889893
}}
890894
>
891-
<Stack direction="row" className="options">
892-
{!isSelf && user.loggedIn && (
893-
<>
894-
<IconButton aria-label="friend user">
895-
<i
896-
className={`fas fa-user-plus ${isFriend ? "sel" : ""}`}
897-
onClick={onFriendUserClick}
895+
<Stack direction="column" spacing={0.5} sx={{ alignItems: "center" }}>
896+
<Stack direction="row" className="options">
897+
{!isSelf && user.loggedIn && (
898+
<>
899+
<IconButton aria-label="friend user">
900+
<i
901+
className={`fas fa-user-plus ${isFriend ? "sel" : ""}`}
902+
onClick={onFriendUserClick}
903+
/>
904+
</IconButton>
905+
{userFamily &&
906+
userFamily.isLeader &&
907+
userFamily.memberCount < 20 && (
908+
<IconButton
909+
aria-label="request to join family"
910+
title={`Invite to ${userFamily.name}`}
911+
>
912+
<i
913+
className="fas fa-users"
914+
onClick={onFamilyJoinRequestClick}
915+
/>
916+
</IconButton>
917+
)}
918+
<LoveIcon
919+
isLove={isLove}
920+
userId={user.id}
921+
isMarried={isMarried}
922+
love={love}
923+
currentUserLove={currentUserLove}
924+
onClick={onLoveUserClick}
898925
/>
899-
</IconButton>
900-
{userFamily &&
901-
userFamily.isLeader &&
902-
userFamily.memberCount < 20 && (
903-
<IconButton
904-
aria-label="request to join family"
905-
title={`Invite to ${userFamily.name}`}
906-
>
907-
<i
908-
className="fas fa-users"
909-
onClick={onFamilyJoinRequestClick}
910-
/>
911-
</IconButton>
912-
)}
913-
<LoveIcon
914-
isLove={isLove}
915-
userId={user.id}
916-
isMarried={isMarried}
917-
love={love}
918-
currentUserLove={currentUserLove}
919-
onClick={onLoveUserClick}
920-
/>
921-
<MarriedIcon
922-
isLove={isLove}
923-
saved={saved}
924-
userId={user.id}
925-
love={love}
926-
isMarried={isMarried}
927-
onClick={onMarryUserClick}
928-
/>
929-
<IconButton aria-label="block user">
930-
<i
931-
className={`fas fa-ban ${isBlocked ? "sel" : ""}`}
932-
onClick={onBlockUserClick}
933-
title="Block user"
926+
<MarriedIcon
927+
isLove={isLove}
928+
saved={saved}
929+
userId={user.id}
930+
love={love}
931+
isMarried={isMarried}
932+
onClick={onMarryUserClick}
934933
/>
935-
</IconButton>
936-
<IconButton size="small" onClick={onReportClick}>
937-
<i className="fas fa-flag" />
938-
</IconButton>
939-
<ReportDialog
940-
open={reportDialogOpen}
941-
onClose={() => setReportDialogOpen(false)}
942-
prefilledArgs={{ userId: profileUserId, userName: name }}
943-
/>
944-
</>
934+
<IconButton aria-label="block user">
935+
<i
936+
className={`fas fa-ban ${isBlocked ? "sel" : ""}`}
937+
onClick={onBlockUserClick}
938+
title="Block user"
939+
/>
940+
</IconButton>
941+
<IconButton size="small" onClick={onReportClick}>
942+
<i className="fas fa-flag" />
943+
</IconButton>
944+
<ReportDialog
945+
open={reportDialogOpen}
946+
onClose={() => setReportDialogOpen(false)}
947+
prefilledArgs={{ userId: profileUserId, userName: name }}
948+
/>
949+
</>
950+
)}
951+
</Stack>
952+
{!isSelf && user.loggedIn && canViewFlagged && (
953+
<Stack direction="row" className="options">
954+
<Tooltip title={isFlagged ? "User is flagged" : "User is not flagged"}>
955+
<IconButton size="small" aria-label="user flagged status">
956+
<i
957+
className="fas fa-flag"
958+
style={{
959+
color: "error.main",
960+
opacity: isFlagged ? 1 : 0.35,
961+
}}
962+
/>
963+
</IconButton>
964+
</Tooltip>
965+
</Stack>
945966
)}
946967
</Stack>
947968
</Grid>

routes/mod.js

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -991,33 +991,6 @@ router.get("/alts", async (req, res) => {
991991
}
992992
});
993993

994-
router.get("/flagged", async (req, res) => {
995-
res.setHeader("Content-Type", "application/json");
996-
try {
997-
var userId = await routeUtils.verifyLoggedIn(req);
998-
var userIdToActOn = String(req.query.userId);
999-
var perm = "viewFlagged";
1000-
1001-
if (!(await routeUtils.verifyPermission(res, userId, perm))) return;
1002-
1003-
var user = await models.User.findOne({
1004-
id: userIdToActOn /*, deleted: false*/,
1005-
}).select("flagged");
1006-
1007-
if (!user) {
1008-
res.status(500);
1009-
res.send("User does not exist.");
1010-
return;
1011-
}
1012-
1013-
res.send(user.flagged);
1014-
} catch (e) {
1015-
logger.error(e);
1016-
res.status(500);
1017-
res.send("Error loading alt accounts.");
1018-
}
1019-
});
1020-
1021994
router.post("/clearSetupName", async (req, res) => {
1022995
res.setHeader("Content-Type", "application/json");
1023996
try {

routes/user.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,39 @@ router.get("/:id/profile", async function (req, res) {
264264
}
265265

266266
var isSelf = reqUserId == userId;
267+
const canViewFlagged = reqUserId
268+
? await redis.hasPermission(reqUserId, "viewFlagged")
269+
: false;
270+
const profileSelectFields = [
271+
"id",
272+
"name",
273+
"avatar",
274+
"profileBackground",
275+
"settings",
276+
"accounts",
277+
"wins",
278+
"losses",
279+
"kudos",
280+
"karma",
281+
"points",
282+
"pointsNegative",
283+
"championshipPoints",
284+
"achievements",
285+
"bio",
286+
"pronouns",
287+
"banner",
288+
"setups",
289+
"games",
290+
"numFriends",
291+
"stats",
292+
"lastActive",
293+
"joined",
294+
"_id",
295+
];
296+
if (canViewFlagged) profileSelectFields.push("flagged");
297+
267298
var user = await models.User.findOne({ id: userId, deleted: false })
268-
.select(
269-
"id name avatar profileBackground settings accounts wins losses kudos karma points pointsNegative championshipPoints achievements bio pronouns banner setups games numFriends stats lastActive joined _id"
270-
)
299+
.select(profileSelectFields.join(" "))
271300
.populate({
272301
path: "setups",
273302
select:

0 commit comments

Comments
 (0)