mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-26 02:39:38 -05:00
Add room sections (#8205)
This commit is contained in:
parent
909d4657f4
commit
a1bdafbfe8
|
|
@ -650,6 +650,14 @@ exports.grouplist = [
|
|||
modchat: true,
|
||||
hiderank: true,
|
||||
},
|
||||
{
|
||||
symbol: '\u25B8',
|
||||
id: "sectionleader",
|
||||
name: "Section Leader",
|
||||
inherit: '+',
|
||||
|
||||
roomonly: true,
|
||||
},
|
||||
{
|
||||
// Bots are ranked below Driver/Mod so that Global Bots can be kept out
|
||||
// of modjoin % rooms (namely, Staff).
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ for (const row of usergroupData) {
|
|||
if (!toID(row)) continue;
|
||||
|
||||
const cells = row.split(',');
|
||||
if (cells.length !== 2) throw new Error(`Invalid entry when parsing usergroups.csv`);
|
||||
if (cells.length > 3) throw new Error(`Invalid entry when parsing usergroups.csv`);
|
||||
usergroups[toID(cells[0])] = cells[1].trim() || ' ';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1704,12 +1704,14 @@ export const commands: ChatCommands = {
|
|||
let group = targetUser.tempGroup;
|
||||
if (targetUser.locked) group = Config.punishgroups?.locked?.symbol ?? '\u203d';
|
||||
if (targetUser.namelocked) group = Config.punishgroups?.namelocked?.symbol ?? '✖';
|
||||
const sectionleader = Users.globalAuth.sectionLeaders.has(targetUser.id);
|
||||
const userdetails: AnyObject = {
|
||||
id: target,
|
||||
userid: targetUser.id,
|
||||
name: targetUser.name,
|
||||
avatar: targetUser.avatar,
|
||||
group: group,
|
||||
customgroup: sectionleader ? "Section Leader" : undefined,
|
||||
autoconfirmed: !!targetUser.autoconfirmed,
|
||||
status: targetUser.getStatus(),
|
||||
rooms: roomList,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
import * as net from 'net';
|
||||
import {YoutubeInterface} from '../chat-plugins/youtube';
|
||||
import {Net, Utils} from '../../lib';
|
||||
import {RoomSections} from './room-settings';
|
||||
|
||||
const ONLINE_SYMBOL = ` \u25C9 `;
|
||||
const OFFLINE_SYMBOL = ` \u25CC `;
|
||||
|
|
@ -102,6 +103,9 @@ export const commands: ChatCommands = {
|
|||
if (Config.groups[targetUser.tempGroup]?.name) {
|
||||
buf += Utils.html`<br />Global ${Config.groups[targetUser.tempGroup].name} (${targetUser.tempGroup})`;
|
||||
}
|
||||
if (Users.globalAuth.sectionLeaders.has(targetUser.id)) {
|
||||
buf += Utils.html`<br />Section Leader (${RoomSections.sectionNames[Users.globalAuth.sectionLeaders.get(targetUser.id)!]})`;
|
||||
}
|
||||
if (targetUser.isSysop) {
|
||||
buf += `<br />(Pokémon Showdown System Operator)`;
|
||||
}
|
||||
|
|
@ -315,6 +319,9 @@ export const commands: ChatCommands = {
|
|||
if (Config.groups[group]?.name) {
|
||||
buf += `<br />Global ${Config.groups[group].name} (${group})`;
|
||||
}
|
||||
if (Users.globalAuth.sectionLeaders.has(userid)) {
|
||||
buf += `<br />Section Leader (${RoomSections.sectionNames[Users.globalAuth.sectionLeaders.get(userid)!]})`;
|
||||
}
|
||||
|
||||
buf += `<br /><br />`;
|
||||
let atLeastOne = false;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
* @license MIT
|
||||
*/
|
||||
import {Utils} from '../../lib';
|
||||
import {RoomSection, RoomSections} from './room-settings';
|
||||
|
||||
/* eslint no-else-return: "error" */
|
||||
|
||||
|
|
@ -101,6 +102,11 @@ export function runPromote(
|
|||
|
||||
export function runCrisisDemote(userid: ID) {
|
||||
const from = [];
|
||||
const section = Users.globalAuth.sectionLeaders.get(userid);
|
||||
if (section) {
|
||||
from.push(`Section Leader (${RoomSections.sectionNames[section] || section})`);
|
||||
Users.globalAuth.deleteSection(userid);
|
||||
}
|
||||
const globalGroup = Users.globalAuth.get(userid);
|
||||
if (globalGroup && globalGroup !== ' ') {
|
||||
from.push(globalGroup);
|
||||
|
|
@ -121,7 +127,6 @@ export function runCrisisDemote(userid: ID) {
|
|||
}
|
||||
|
||||
export const commands: ChatCommands = {
|
||||
|
||||
roomowner(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) {
|
||||
|
|
@ -374,6 +379,10 @@ export const commands: ChatCommands = {
|
|||
if (group !== ' ' || Users.isTrusted(targetId)) {
|
||||
buffer.push(`Global auth: ${group === ' ' ? 'trusted' : group}`);
|
||||
}
|
||||
const sectionLeader = Users.globalAuth.sectionLeaders.get(targetId);
|
||||
if (sectionLeader) {
|
||||
buffer.push(`Section leader: ${RoomSections.sectionNames[sectionLeader]}`);
|
||||
}
|
||||
for (const curRoom of Rooms.rooms.values()) {
|
||||
if (curRoom.settings.isPrivate) continue;
|
||||
if (!curRoom.auth.has(targetId)) continue;
|
||||
|
|
@ -414,6 +423,25 @@ export const commands: ChatCommands = {
|
|||
connection.popup(buffer.join("\n\n"));
|
||||
},
|
||||
|
||||
sectionleaders(target, room, user, connection) {
|
||||
const usernames = Users.globalAuth.usernames;
|
||||
const buffer = [];
|
||||
const sections: {[k in RoomSection]: Set<string>} = Object.create(null);
|
||||
for (const [id, username] of usernames) {
|
||||
const sectionid = Users.globalAuth.sectionLeaders.get(id);
|
||||
if (!sectionid) continue;
|
||||
if (!sections[sectionid]) sections[sectionid] = new Set();
|
||||
sections[sectionid].add(username);
|
||||
}
|
||||
let sectionid: RoomSection;
|
||||
for (sectionid in sections) {
|
||||
if (!sections[sectionid].size) continue;
|
||||
buffer.push(`**${RoomSections.sectionNames[sectionid]}**:\n` + [...sections[sectionid]].join(', '));
|
||||
}
|
||||
if (!buffer.length) throw new Chat.ErrorMessage(`There are no Section Leaders currently.`);
|
||||
connection.popup(buffer.join(`\n\n`));
|
||||
},
|
||||
|
||||
async autojoin(target, room, user, connection) {
|
||||
const targets = target.split(',');
|
||||
if (targets.length > 16 || connection.inRooms.size > 1) {
|
||||
|
|
@ -1363,6 +1391,57 @@ export const commands: ChatCommands = {
|
|||
`/untrustuser [username] - Removes the trusted user status from the user. Requires: &`,
|
||||
],
|
||||
|
||||
desectionleader: 'sectionleader',
|
||||
sectionleader(target, room, user, connection, cmd) {
|
||||
this.checkCan('gdeclare');
|
||||
room = this.requireRoom();
|
||||
const demoting = cmd === 'desectionleader';
|
||||
if (!target || (target.split(',').length < 2 && !demoting)) return this.parse(`/help sectionleader`);
|
||||
|
||||
const [targetStr, sectionid] = this.splitOne(target);
|
||||
this.splitTarget(targetStr);
|
||||
const targetUser = this.targetUser;
|
||||
const userid = toID(this.targetUsername);
|
||||
const section = demoting ? Users.globalAuth.sectionLeaders.get(userid)! : room.validateSection(sectionid);
|
||||
const name = targetUser ? targetUser.name : this.targetUsername;
|
||||
if (Users.globalAuth.sectionLeaders.has(targetUser?.id || userid) && !demoting) {
|
||||
throw new Chat.ErrorMessage(`${name} is already a Section Leader of ${RoomSections.sectionNames[section]}.`);
|
||||
} else if (!Users.globalAuth.sectionLeaders.has(targetUser?.id || userid) && demoting) {
|
||||
throw new Chat.ErrorMessage(`${name} is not a Section Leader.`);
|
||||
}
|
||||
const staffRoom = Rooms.get('staff');
|
||||
if (!demoting) {
|
||||
Users.globalAuth.setSection(userid, section);
|
||||
this.addGlobalModAction(`${name} was appointed Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
|
||||
this.globalModlog(`SECTION LEADER`, userid, section);
|
||||
if (!staffRoom?.auth.has(userid)) this.parse(`/msgroom staff,/forceroompromote ${userid},▸`);
|
||||
targetUser?.popup(`You were appointed Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
|
||||
} else {
|
||||
const group = Users.globalAuth.get(userid);
|
||||
Users.globalAuth.deleteSection(userid);
|
||||
this.privateGlobalModAction(`${name} was demoted from Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
|
||||
if (group === ' ') this.sendReply(`They are also no longer manually trusted. If they should be, use '/trustuser'.`);
|
||||
this.globalModlog(`DESECTION LEADER`, userid, section);
|
||||
if (staffRoom?.auth.getDirect(userid) as any === '\u25B8') this.parse(`/msgroom staff,/roomdeauth ${userid}`);
|
||||
targetUser?.popup(`You were demoted from Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
|
||||
}
|
||||
|
||||
if (targetUser) {
|
||||
targetUser.updateIdentity();
|
||||
Rooms.global.checkAutojoin(targetUser);
|
||||
if (targetUser.trusted && !Users.isTrusted(targetUser.id)) {
|
||||
targetUser.trusted = '';
|
||||
}
|
||||
}
|
||||
},
|
||||
sectionleaderhelp: [
|
||||
`/sectionleader [target user], [sectionid] - Appoints [target user] Section Leader.`,
|
||||
`/desectionleader [target user] - Demotes [target user] from Section Leader.`,
|
||||
`Valid sections: ${RoomSections.sections.join(', ')}`,
|
||||
`If you want to change which section someone leads, demote them and then re-promote them in the desired section.`,
|
||||
`Requires: &`,
|
||||
],
|
||||
|
||||
globaldemote: 'demote',
|
||||
demote(target) {
|
||||
if (!target) return this.parse('/help demote');
|
||||
|
|
|
|||
|
|
@ -15,6 +15,25 @@ const SLOWCHAT_MINIMUM = 2;
|
|||
const SLOWCHAT_MAXIMUM = 60;
|
||||
const SLOWCHAT_USER_REQUIREMENT = 10;
|
||||
|
||||
export const sections = [
|
||||
'official', 'battleformats', 'languages', 'entertainment', 'gaming', 'lifehobbies', 'onsitegames',
|
||||
] as const;
|
||||
|
||||
export type RoomSection = typeof sections[number];
|
||||
|
||||
export const RoomSections: {sectionNames: {[k in RoomSection]: string}, sections: readonly RoomSection[]} = {
|
||||
sectionNames: {
|
||||
official: 'Official',
|
||||
battleformats: 'Battle formats',
|
||||
languages: 'Languages',
|
||||
entertainment: 'Entertainment',
|
||||
gaming: 'Gaming',
|
||||
lifehobbies: 'Life & hobbies',
|
||||
onsitegames: 'On-site games',
|
||||
},
|
||||
sections,
|
||||
};
|
||||
|
||||
export const commands: ChatCommands = {
|
||||
roomsetting: 'roomsettings',
|
||||
roomsettings(target, room, user, connection) {
|
||||
|
|
@ -1085,6 +1104,7 @@ export const commands: ChatCommands = {
|
|||
}
|
||||
this.addModAction(`${user.name} made this room ${settingName}.`);
|
||||
this.modlog(`${settingName.toUpperCase()}ROOM`);
|
||||
if (!room.settings.isPersonal && !room.battle) room.setSection();
|
||||
room.setPrivate(setting);
|
||||
room.privacySetter = new Set([user.id]);
|
||||
}
|
||||
|
|
@ -1114,48 +1134,27 @@ export const commands: ChatCommands = {
|
|||
],
|
||||
|
||||
officialchatroom: 'officialroom',
|
||||
officialroom(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('makeroom');
|
||||
if (!room.persist) {
|
||||
return this.errorReply(`/officialroom - This room can't be made official`);
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
if (!room.settings.isOfficial) return this.errorReply(`This chat room is already unofficial.`);
|
||||
delete room.settings.isOfficial;
|
||||
this.addModAction(`${user.name} made this chat room unofficial.`);
|
||||
this.modlog('UNOFFICIALROOM');
|
||||
delete room.settings.isOfficial;
|
||||
room.saveSettings();
|
||||
} else {
|
||||
if (room.settings.isOfficial) return this.errorReply(`This chat room is already official.`);
|
||||
room.settings.isOfficial = true;
|
||||
this.addModAction(`${user.name} made this chat room official.`);
|
||||
this.modlog('OFFICIALROOM');
|
||||
room.settings.isOfficial = true;
|
||||
room.saveSettings();
|
||||
}
|
||||
officialroom() {
|
||||
this.parse(`/setroomsection official`);
|
||||
},
|
||||
|
||||
psplwinnerroom(target, room, user) {
|
||||
this.checkCan('makeroom');
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) {
|
||||
return this.errorReply(`/psplwinnerroom - This room can't be marked as a PSPL Winner room`);
|
||||
return this.errorReply(`/psplwinnerroom - This room can't be marked as a PSPL Winner room.`);
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
if (!room.settings.pspl) return this.errorReply(`This chat room is already not a PSPL Winner room.`);
|
||||
delete room.settings.pspl;
|
||||
this.addModAction(`${user.name} made this chat room no longer a PSPL Winner room.`);
|
||||
this.modlog('PSPLROOM');
|
||||
this.globalModlog('UNPSPLROOM');
|
||||
delete room.settings.pspl;
|
||||
room.saveSettings();
|
||||
} else {
|
||||
if (room.settings.pspl) return this.errorReply("This chat room is already a PSPL Winner room.");
|
||||
room.settings.pspl = true;
|
||||
this.addModAction(`${user.name} made this chat room a PSPL Winner room.`);
|
||||
this.modlog('UNPSPLROOM');
|
||||
room.settings.pspl = true;
|
||||
this.globalModlog('PSPLROOM');
|
||||
room.settings.pspl = "PSPL Winner";
|
||||
room.saveSettings();
|
||||
}
|
||||
},
|
||||
|
|
@ -1486,6 +1485,27 @@ export const commands: ChatCommands = {
|
|||
`/roomtierdisplay [option] - changes the current room's tier display. Valid options are: tiers, doubles tiers, numbers. Requires: # &`,
|
||||
`/resettierdisplay - resets the current room's tier display. Requires: # &`,
|
||||
],
|
||||
|
||||
setroomsection: 'roomsection',
|
||||
roomsection(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const sectionNames = RoomSections.sectionNames;
|
||||
if (!target) {
|
||||
if (!this.runBroadcast()) return;
|
||||
this.sendReplyBox(Utils.html`This room is ${room.settings.section ? `in the ${sectionNames[room.settings.section]} section` : `not in a section`}.`);
|
||||
return;
|
||||
}
|
||||
this.checkCan('gdeclare');
|
||||
const section = room.setSection(target);
|
||||
this.sendReply(`The room section is now: ${section ? sectionNames[section] : 'none'}`);
|
||||
|
||||
this.privateGlobalModAction(`${user.name} changed the room section of ${room.title} to ${section ? sectionNames[section] : 'none'}.`);
|
||||
this.globalModlog('ROOMSECTION', null, section || 'none');
|
||||
},
|
||||
roomsectionhelp: [
|
||||
`/roomsection [section] - Sets the room this is used in to the specified [section]. Requires: &`,
|
||||
`Valid sections: ${sections.join(', ')}`,
|
||||
],
|
||||
};
|
||||
|
||||
export const roomSettings: SettingsHandler[] = [
|
||||
|
|
@ -1586,7 +1606,7 @@ export const pages: PageTable = {
|
|||
atLeastOne = true;
|
||||
buf += `<tr><td><strong>${permission}</strong></td><td>`;
|
||||
if (room.auth.atLeast(user, '#')) {
|
||||
buf += roomGroups.map(group => (
|
||||
buf += roomGroups.filter(group => group !== Users.SECTIONLEADER_SYMBOL).map(group => (
|
||||
requiredRank === group ?
|
||||
Utils.html`<button class="button disabled" style="font-weight:bold;color:#575757;background:#d3d3d3">${group}</button>` :
|
||||
Utils.html`<button class="button" name="send" value="/msgroom ${room.roomid},/permissions set ${permission}, ${group}">${group}</button>`
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ export const LogReader = new class {
|
|||
}
|
||||
} else if (!room) {
|
||||
if (opts === 'all' || opts === 'deleted') deleted.push(roomid);
|
||||
} else if (room.settings.isOfficial) {
|
||||
} else if (room.settings.section === 'official') {
|
||||
official.push(roomid);
|
||||
} else if (!room.settings.isPrivate) {
|
||||
normal.push(roomid);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const LAST_BATTLE_WRITE_THROTTLE = 10;
|
|||
const RETRY_AFTER_LOGIN = null;
|
||||
|
||||
import {FS, Utils, Streams} from '../lib';
|
||||
import {RoomSection, RoomSections} from './chat-commands/room-settings';
|
||||
import {GTSGiveaway, LotteryGiveaway, QuestionGiveaway} from './chat-plugins/wifi';
|
||||
import {QueuedHunt} from './chat-plugins/scavengers';
|
||||
import {ScavengerGameTemplate} from './chat-plugins/scavenger-games';
|
||||
|
|
@ -56,7 +57,9 @@ interface ChatRoomTable {
|
|||
title: string;
|
||||
desc: string;
|
||||
userCount: number;
|
||||
section?: string;
|
||||
subRooms?: string[];
|
||||
spotlight?: string;
|
||||
}
|
||||
|
||||
interface ShowRequest {
|
||||
|
|
@ -80,6 +83,7 @@ export interface RoomSettings {
|
|||
title: string;
|
||||
auth: {[userid: string]: GroupSymbol};
|
||||
creationTime: number;
|
||||
section?: RoomSection;
|
||||
|
||||
readonly autojoin?: boolean;
|
||||
aliases?: string[];
|
||||
|
|
@ -101,8 +105,7 @@ export interface RoomSettings {
|
|||
hangmanDisabled?: boolean;
|
||||
gameNumber?: number;
|
||||
highTraffic?: boolean;
|
||||
isOfficial?: boolean;
|
||||
pspl?: boolean;
|
||||
pspl?: string;
|
||||
parentid?: string | null;
|
||||
desc?: string | null;
|
||||
introMessage?: string | null;
|
||||
|
|
@ -697,7 +700,7 @@ export abstract class BasicRoom {
|
|||
}
|
||||
message += `</div>`;
|
||||
if (this.settings.introMessage) {
|
||||
message += `\n|raw|<div class="infobox infobox-roomintro"><div ${(!this.settings.isOfficial ? 'class="infobox-limited"' : '')}>` +
|
||||
message += `\n|raw|<div class="infobox infobox-roomintro"><div ${(this.settings.section !== 'official' ? 'class="infobox-limited"' : '')}>` +
|
||||
this.settings.introMessage.replace(/\n/g, '') +
|
||||
`</div></div>`;
|
||||
}
|
||||
|
|
@ -824,6 +827,34 @@ export abstract class BasicRoom {
|
|||
}
|
||||
}
|
||||
}
|
||||
validateSection(section: string) {
|
||||
const target = toID(section);
|
||||
if (!RoomSections.sections.includes(target as any)) {
|
||||
throw new Chat.ErrorMessage(`"${target}" is not a valid room section. Valid categories include: ${RoomSections.sections.join(', ')}`);
|
||||
}
|
||||
return target as RoomSection;
|
||||
}
|
||||
setSection(section?: string) {
|
||||
if (!this.persist) {
|
||||
throw new Chat.ErrorMessage(`You cannot change the section of temporary rooms.`);
|
||||
}
|
||||
if (section) {
|
||||
const validatedSection = this.validateSection(section);
|
||||
if (this.settings.isPrivate && [true, 'hidden'].includes(this.settings.isPrivate)) {
|
||||
throw new Chat.ErrorMessage(`Only public rooms can change their section.`);
|
||||
}
|
||||
const oldSection = this.settings.section;
|
||||
if (oldSection === section) {
|
||||
throw new Chat.ErrorMessage(`${this.title}'s room section is already set to "${RoomSections.sectionNames[oldSection]}".`);
|
||||
}
|
||||
this.settings.section = validatedSection;
|
||||
this.saveSettings();
|
||||
return validatedSection;
|
||||
}
|
||||
delete this.settings.section;
|
||||
this.saveSettings();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a warning popup to all non-staff users users in the room.
|
||||
|
|
@ -1123,8 +1154,8 @@ export class GlobalRoomState {
|
|||
title: 'Lobby',
|
||||
auth: {},
|
||||
creationTime: Date.now(),
|
||||
isOfficial: true,
|
||||
autojoin: true,
|
||||
section: 'official',
|
||||
}, {
|
||||
title: 'Staff',
|
||||
auth: {},
|
||||
|
|
@ -1353,11 +1384,13 @@ export class GlobalRoomState {
|
|||
}
|
||||
getRooms(user: User) {
|
||||
const roomsData: {
|
||||
official: ChatRoomTable[], pspl: ChatRoomTable[], chat: ChatRoomTable[], userCount: number, battleCount: number,
|
||||
chat: ChatRoomTable[],
|
||||
sectionTitles: string[],
|
||||
userCount: number,
|
||||
battleCount: number,
|
||||
} = {
|
||||
official: [],
|
||||
pspl: [],
|
||||
chat: [],
|
||||
sectionTitles: Object.values(RoomSections.sectionNames),
|
||||
userCount: Users.onlineCount,
|
||||
battleCount: this.battleCount,
|
||||
};
|
||||
|
|
@ -1369,18 +1402,14 @@ export class GlobalRoomState {
|
|||
title: room.title,
|
||||
desc: room.settings.desc || '',
|
||||
userCount: room.userCount,
|
||||
section: room.settings.section ?
|
||||
(RoomSections.sectionNames[room.settings.section] || room.settings.section) : undefined,
|
||||
};
|
||||
const subrooms = room.getSubRooms().map(r => r.title);
|
||||
if (subrooms.length) roomData.subRooms = subrooms;
|
||||
if (room.settings.pspl) roomData.spotlight = room.settings.pspl;
|
||||
|
||||
if (room.settings.isOfficial) {
|
||||
roomsData.official.push(roomData);
|
||||
// @ts-ignore
|
||||
} else if (room.pspl) {
|
||||
roomsData.pspl.push(roomData);
|
||||
} else {
|
||||
roomsData.chat.push(roomData);
|
||||
}
|
||||
roomsData.chat.push(roomData);
|
||||
}
|
||||
return roomsData;
|
||||
}
|
||||
|
|
@ -1853,7 +1882,7 @@ export const Rooms = {
|
|||
Rooms.rooms.set(roomid, room);
|
||||
return room;
|
||||
},
|
||||
createChatRoom(roomid: RoomID, title: string, options: AnyObject) {
|
||||
createChatRoom(roomid: RoomID, title: string, options: Partial<RoomSettings>) {
|
||||
if (Rooms.rooms.has(roomid)) throw new Error(`Room ${roomid} already exists`);
|
||||
const room: ChatRoom = new (BasicRoom as any)(roomid, title, options);
|
||||
Rooms.rooms.set(roomid, room);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import {FS} from '../lib/fs';
|
||||
import type {RoomSection} from './chat-commands/room-settings';
|
||||
|
||||
export type GroupSymbol = '~' | '&' | '#' | '★' | '*' | '@' | '%' | '☆' | '+' | ' ' | '‽' | '!';
|
||||
export type GroupSymbol = '~' | '&' | '#' | '★' | '*' | '@' | '%' | '☆' | '▸' | '+' | '^' | ' ' | '‽' | '!';
|
||||
export type EffectiveGroupSymbol = GroupSymbol | 'whitelist';
|
||||
export type AuthLevel = EffectiveGroupSymbol | 'unlocked' | 'trusted' | 'autoconfirmed';
|
||||
|
||||
export const SECTIONLEADER_SYMBOL: GroupSymbol = '\u25B8';
|
||||
export const PLAYER_SYMBOL: GroupSymbol = '\u2606';
|
||||
export const HOST_SYMBOL: GroupSymbol = '\u2605';
|
||||
|
||||
export const ROOM_PERMISSIONS = [
|
||||
'addhtml', 'announce', 'ban', 'bypassafktimer', 'declare', 'editprivacy', 'editroom', 'exportinputlog', 'game', 'gamemanagement', 'gamemoderation', 'joinbattle', 'kick', 'minigame', 'modchat', 'modlog', 'mute', 'nooverride', 'receiveauthmessages', 'roombot', 'roomdriver', 'roommod', 'roomowner', 'roomvoice', 'roomprizewinner', 'show', 'showmedia', 'timer', 'tournaments', 'warn',
|
||||
'addhtml', 'announce', 'ban', 'bypassafktimer', 'declare', 'editprivacy', 'editroom', 'exportinputlog', 'game', 'gamemanagement', 'gamemoderation', 'joinbattle', 'kick', 'minigame', 'modchat', 'modlog', 'mute', 'nooverride', 'receiveauthmessages', 'roombot', 'roomdriver', 'roommod', 'roomowner', 'roomsectionleader', 'roomvoice', 'roomprizewinner', 'show', 'showmedia', 'timer', 'tournaments', 'warn',
|
||||
] as const;
|
||||
|
||||
export const GLOBAL_PERMISSIONS = [
|
||||
|
|
@ -307,6 +309,7 @@ export class RoomAuth extends Auth {
|
|||
|
||||
export class GlobalAuth extends Auth {
|
||||
usernames = new Map<ID, string>();
|
||||
sectionLeaders = new Map<ID, RoomSection>();
|
||||
constructor() {
|
||||
super();
|
||||
this.load();
|
||||
|
|
@ -315,7 +318,7 @@ export class GlobalAuth extends Auth {
|
|||
FS('config/usergroups.csv').writeUpdate(() => {
|
||||
let buffer = '';
|
||||
for (const [userid, groupSymbol] of this) {
|
||||
buffer += `${this.usernames.get(userid) || userid},${groupSymbol}\n`;
|
||||
buffer += `${this.usernames.get(userid) || userid},${groupSymbol},${this.sectionLeaders.get(userid) || ''}\n`;
|
||||
}
|
||||
return buffer;
|
||||
});
|
||||
|
|
@ -324,9 +327,10 @@ export class GlobalAuth extends Auth {
|
|||
const data = FS('config/usergroups.csv').readIfExistsSync();
|
||||
for (const row of data.split("\n")) {
|
||||
if (!row) continue;
|
||||
const [name, symbol] = row.split(",");
|
||||
const [name, symbol, sectionid] = row.split(",");
|
||||
const id = toID(name);
|
||||
this.usernames.set(id, name);
|
||||
if (sectionid) this.sectionLeaders.set(id, sectionid as RoomSection);
|
||||
super.set(id, symbol.charAt(0) as GroupSymbol);
|
||||
}
|
||||
}
|
||||
|
|
@ -355,4 +359,31 @@ export class GlobalAuth extends Auth {
|
|||
this.save();
|
||||
return true;
|
||||
}
|
||||
setSection(id: ID, sectionid: RoomSection, username?: string) {
|
||||
if (!username) username = id;
|
||||
const user = Users.get(id);
|
||||
if (user) {
|
||||
user.updateIdentity();
|
||||
username = user.name;
|
||||
Rooms.global.checkAutojoin(user);
|
||||
}
|
||||
if (!super.has(id)) this.set(id, ' ', username);
|
||||
this.sectionLeaders.set(id, sectionid);
|
||||
void this.save();
|
||||
return this;
|
||||
}
|
||||
deleteSection(id: ID) {
|
||||
if (!this.sectionLeaders.has(id)) return false;
|
||||
this.sectionLeaders.delete(id);
|
||||
if (super.get(id) === ' ') {
|
||||
return this.delete(id);
|
||||
}
|
||||
const user = Users.get(id);
|
||||
if (user) {
|
||||
user.updateIdentity();
|
||||
Rooms.global.checkAutojoin(user);
|
||||
}
|
||||
this.save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ const PERMALOCK_CACHE_TIME = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|||
const DEFAULT_TRAINER_SPRITES = [1, 2, 101, 102, 169, 170, 265, 266];
|
||||
|
||||
import {FS, Utils, ProcessManager} from '../lib';
|
||||
import {Auth, GlobalAuth, PLAYER_SYMBOL, HOST_SYMBOL, RoomPermission, GlobalPermission} from './user-groups';
|
||||
import {
|
||||
Auth, GlobalAuth, SECTIONLEADER_SYMBOL, PLAYER_SYMBOL, HOST_SYMBOL, RoomPermission, GlobalPermission,
|
||||
} from './user-groups';
|
||||
|
||||
const MINUTES = 60 * 1000;
|
||||
const IDLE_TIMER = 60 * MINUTES;
|
||||
|
|
@ -1703,6 +1705,7 @@ export const Users = {
|
|||
globalAuth,
|
||||
isUsernameKnown,
|
||||
isTrusted,
|
||||
SECTIONLEADER_SYMBOL,
|
||||
PLAYER_SYMBOL,
|
||||
HOST_SYMBOL,
|
||||
connections,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ describe('Rooms features', function () {
|
|||
});
|
||||
|
||||
it('should copy auth from tournament', function () {
|
||||
parent = Rooms.createChatRoom('parentroom', '', {});
|
||||
parent = Rooms.createChatRoom('parentroom');
|
||||
parent.auth.get = () => '%';
|
||||
const p1 = makeUser();
|
||||
const p2 = makeUser();
|
||||
|
|
@ -86,7 +86,7 @@ describe('Rooms features', function () {
|
|||
});
|
||||
|
||||
it('should prevent overriding tournament room auth by a tournament player', function () {
|
||||
parent = Rooms.createChatRoom('parentroom2', '', {});
|
||||
parent = Rooms.createChatRoom('parentroom2');
|
||||
parent.auth.get = () => '%';
|
||||
const p1 = makeUser();
|
||||
const p2 = makeUser();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user