pixelplanet/src/core/ChatProvider.js

249 lines
6.6 KiB
JavaScript

/* @flow */
import logger from './logger';
import redis from '../data/redis';
import User from '../data/models/User';
import webSockets from '../socket/websockets';
import { CHAT_CHANNELS } from './constants';
export class ChatProvider {
/*
* TODO:
* history really be saved in redis
*/
history: Array;
constructor() {
this.history = [];
for (let i = 0; i < CHAT_CHANNELS.length; i += 1) {
this.history.push([]);
}
this.caseCheck = /^[A-Z !.]*$/;
this.filters = [
{
regexp: /ADMIN/gi,
matches: 4,
},
{
regexp: /ADMlN/gi,
matches: 4,
},
{
regexp: /ADMlN/gi,
matches: 4,
},
{
regexp: /FUCK/gi,
matches: 4,
},
];
this.substitutes = [
{
regexp: /http[s]?:\/\/(old.)?pixelplanet\.fun\/#/g,
replace: '#',
},
];
this.mutedCountries = [];
}
addMessage(name, message, country, channelId = 0) {
const channelHistory = this.history[channelId];
if (channelHistory.length > 20) {
channelHistory.shift();
}
channelHistory.push([name, message, country]);
}
async sendMessage(user, message, channelId: number = 0) {
const name = (user.regUser) ? user.regUser.name : null;
const country = user.country || 'xx';
let displayCountry = (name.endsWith('berg') || name.endsWith('stein'))
? 'il'
: country;
if (!name) {
// eslint-disable-next-line max-len
return 'Couldn\'t send your message, pls log out and back in again.';
}
if (!user.regUser.verified) {
return 'Your mail has to be verified in order to chat';
}
if (name === 'Aquila') {
displayCountry = 'ug';
}
if (message.length > 2
&& message === message.toUpperCase()
&& message !== message.toLowerCase()
) {
return 'Stop shouting';
}
for (let i = 0; i < this.filters.length; i += 1) {
const filter = this.filters[i];
const count = (message.match(filter.regexp) || []).length;
if (count >= filter.matches) {
ChatProvider.mute(name, channelId, 30);
return 'Ow no! Spam protection decided to mute you';
}
}
for (let i = 0; i < this.substitutes.length; i += 1) {
const subsitute = this.substitutes[i];
message = message.replace(subsitute.regexp, subsitute.replace);
}
if (message.includes('http')) {
return 'no shitty links pls';
}
if (message.length > 200) {
// eslint-disable-next-line max-len
return 'You can\'t send a message this long :(';
}
if (user.isAdmin() && message.charAt(0) === '/') {
// admin commands
const cmdArr = message.split(' ');
const cmd = cmdArr[0].substr(1);
const args = cmdArr.slice(1);
if (cmd === 'mute') {
const timeMin = Number(args.slice(-1));
if (Number.isNaN(timeMin)) {
return ChatProvider.mute(args.join(' '), channelId);
}
return ChatProvider.mute(
args.slice(0, -1).join(' '),
channelId,
timeMin,
);
} if (cmd === 'unmute') {
return ChatProvider.unmute(args.join(' '), channelId);
} if (cmd === 'mutec' && args[0]) {
const cc = args[0].toLowerCase();
this.mutedCountries.push(cc);
webSockets.broadcastChatMessage(
'info',
`Country ${cc} has been muted`,
channelId,
);
return null;
} if (cmd === 'unmutec' && args[0]) {
const cc = args[0].toLowerCase();
if (!this.mutedCountries.includes(cc)) {
return `Country ${cc} is not muted`;
}
this.mutedCountries = this.mutedCountries.filter((c) => c !== cc);
webSockets.broadcastChatMessage(
'info',
`Country ${cc} has been unmuted`,
channelId,
);
return null;
}
}
if (this.mutedCountries.includes(country)) {
return 'Your country is temporary muted from chat';
}
const muted = await ChatProvider.checkIfMuted(user);
if (muted === -1) {
return 'You are permanently muted, join our discord to apppeal the mute';
}
if (muted > 0) {
if (muted > 120) {
const timeMin = Math.round(muted / 60);
return `You are muted for another ${timeMin} minutes`;
}
return `You are muted for another ${muted} seconds`;
}
this.addMessage(name, message, displayCountry, channelId);
webSockets.broadcastChatMessage(name, message, displayCountry, channelId);
return null;
}
broadcastChatMessage(
name,
message,
country: string = 'xx',
channelId: number = 0,
sendapi: boolean = true,
) {
if (message.length > 250) {
return;
}
this.addMessage(name, message, country, channelId);
webSockets.broadcastChatMessage(name, message, country, channelId, sendapi);
}
static automute(name, channelId = 0) {
ChatProvider.mute(name, channelId, 60);
webSockets.broadcastChatMessage(
'info',
`${name} has been muted for spam for 60min`,
channelId,
);
}
static async checkIfMuted(user) {
const key = `mute:${user.id}`;
const ttl: number = await redis.ttlAsync(key);
return ttl;
}
static async mute(plainName, channelId = 0, timeMin = null) {
const name = (plainName.startsWith('@')) ? plainName.substr(1) : plainName;
const id = await User.name2Id(name);
if (!id) {
return `Couldn't find user ${name}`;
}
const key = `mute:${id}`;
if (timeMin) {
const ttl = timeMin * 60;
await redis.setAsync(key, '', 'EX', ttl);
if (timeMin !== 600 && timeMin !== 60) {
webSockets.broadcastChatMessage(
'info',
`${name} has been muted for ${timeMin}min`,
channelId,
);
}
} else {
await redis.setAsync(key, '');
webSockets.broadcastChatMessage(
'info',
`${name} has been muted forever`,
channelId,
);
}
logger.info(`Muted user ${id}`);
return null;
}
static async unmute(plainName, channelId = 0) {
const name = (plainName.startsWith('@')) ? plainName.substr(1) : plainName;
const id = await User.name2Id(name);
if (!id) {
return `Couldn't find user ${name}`;
}
const key = `mute:${id}`;
const delKeys = await redis.delAsync(key);
if (delKeys !== 1) {
return `User ${name} is not muted`;
}
webSockets.broadcastChatMessage(
'info',
`${name} has been unmuted`,
channelId,
);
logger.info(`Unmuted user ${id}`);
return null;
}
}
const chatProvider = new ChatProvider();
export default chatProvider;