Skip to content

Commit

Permalink
Merge pull request #142 from destinygg/gulag-voteban-fix
Browse files Browse the repository at this point in the history
Fix gulag and voteban commands
  • Loading branch information
11k authored Feb 20, 2024
2 parents ea02e6c + b5c5537 commit b816bf7
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 127 deletions.
10 changes: 10 additions & 0 deletions lib/chat-utils/parse-commands-from-chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ function formatUnban(user) {
return `UNBAN ${JSON.stringify({ data: user })}`;
}

function formatPoll(weighted, time, question, options) {
return `STARTPOLL ${JSON.stringify({
weighted,
time,
question,
options,
})}`;
}

function parseMessage(message) {
const parsed = JSON.parse(message.replace('MSG ', ''));
return { user: parsed.nick, roles: parsed.features, message: parsed.data };
Expand Down Expand Up @@ -59,6 +68,7 @@ module.exports = {
formatUnmute,
formatBan,
formatUnban,
formatPoll,
parseWhisper,
formatWhisper,
};
2 changes: 1 addition & 1 deletion lib/commands/implementations/breaking-news.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function breakingNews(defaultMaxAge) {
const formattedMaxAge = formatDuration(moment.duration(maxAge, 'seconds'));

const listener = services.messageRelay.startListenerForChatMessages('breakingnews');
listener.on('message', (data) => {
listener.on('msg', (data) => {
const message = data.message.trim().toLowerCase();
if (state !== 'all' && !services.messageMatching.mentionsUser(message, mentionUser)) return;
if (!services.messageMatching.hasLink(message)) return;
Expand Down
117 changes: 74 additions & 43 deletions lib/commands/implementations/gulag.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,32 @@ const Command = require('../command-interface');
const CommandOutput = require('../command-output');
const { makeBan } = require('../../chat-utils/punishment-helpers');

function isNormalInteger(str) {
const n = Math.floor(Number(str));
return n !== Infinity && String(n) === str && n >= 0;
}
let gulagStarted = false;
function gulag(defaultBanTime) {
const pollDuration = 30000;

let failSafeTimeout = null;
let gulagActive = false;

return (input, services, rawMessage) => {
if (gulagStarted) {
if (gulagActive) {
return new CommandOutput(
null,
'Gulag in progress. Please wait for the current vote to finish.',
'Gulag in progress. Please wait for the current gulag to finish.',
);
}

const {
isPermanent,
parsedDuration,
muteString,
users: parsedUsers,
} = services.gulag.parseInput(input, defaultBanTime);

if (parsedUsers.length > 5) {
return new CommandOutput(null, 'Too many users to be sent to the gulag, max of 5.');
}
gulagStarted = true;
const listener = services.messageRelay.startListenerForChatMessages('gulag');
if (listener === false) {
return new CommandOutput(null, 'Something went wrong?? uhh. Restart me.');
}
const votedMap = {};

// FIXME: There's a chance that a random user is already in the list, reducing the number of expected users.
const users = _.uniq(
parsedUsers.map((name) => {
if (name.toLowerCase() === 'random') {
Expand All @@ -39,52 +37,85 @@ function gulag(defaultBanTime) {
return name;
}),
);
const userVotes = users.map((name) => ({ name, value: 0 }));
listener.on('message', (data) => {
if (votedMap[data.user]) {
return;
}
const message = data.message.trim();
if (isNormalInteger(message)) {
const int = parseInt(message, 10);
if (int >= 1 && int <= users.length) {
votedMap[data.user] = true;
userVotes[int - 1].value += 1;
}

const listener = services.messageRelay.startListenerForChatMessages('gulag');
if (listener === false) {
return new CommandOutput(null, 'Something went wrong?? uhh. Restart me.');
}

listener.on('err', (message) => {
const error = JSON.parse(message);
if (error.description === 'activepoll' && !gulagActive) {
clearTimeout(failSafeTimeout);
services.messageRelay.stopRelay('gulag');
services.messageRelay.sendOutputMessage(
'Poll in progress. Please wait for the current poll to finish.',
);
}
});
setTimeout(() => {
gulagStarted = false;

listener.on('pollstart', () => {
gulagActive = true;
services.messageRelay.sendOutputMessage(
`ENTER THE GULAG. Chatters battling it out to not get a ${muteString} ban. Vote KEEP not KICK!? ${users.join(
' vs ',
)}`,
);

// Fail-safe
failSafeTimeout = setTimeout(() => {
gulagActive = false;
services.messageRelay.stopRelay('gulag');
}, pollDuration + 5000);
});

listener.on('pollstop', (message) => {
clearTimeout(failSafeTimeout);
gulagActive = false;
services.messageRelay.stopRelay('gulag');
services.messageRelay.sendOutputMessage('Total votes:');
userVotes.forEach((user) => {
services.messageRelay.sendOutputMessage(`${user.name} votes: ${user.value}`);

services.messageRelay.sendOutputMessage('GULAG has ended:');

const poll = JSON.parse(message);
const winnerVotes = Math.max(...poll.totals);
const winners = [];
const losers = [];
poll.totals.forEach((votes, index) => {
if (votes === winnerVotes) {
winners.push({ user: poll.options[index], votes });
} else {
losers.push({ user: poll.options[index], votes });
}
});
const firstWinner = _.maxBy(userVotes, 'value');
const winners = userVotes.filter((user) => user.value === firstWinner.value);
const losers = userVotes.filter((user) => user.value !== firstWinner.value);
winners.forEach((user) => {
winners.forEach(({ user, votes }) => {
services.messageRelay.sendOutputMessage(
`${user.name} has won the most votes and will be released from the gulag AYAYA`,
`${user} has won the most votes and will be released from the gulag AYAYA . Votes: ${votes}`,
);
});
losers.forEach((user) => {
losers.forEach(({ user, votes }) => {
services.punishmentStream.write(
makeBan(
user.name,
user,
parsedDuration,
false,
isPermanent,
`${user.name} banned through bot by GULAG battle started by ${rawMessage.user}. Votes: ${user.value}`,
`${user} banned through bot by GULAG battle started by ${rawMessage.user}. Votes: ${votes}`,
),
);
});
}, 30500);
const userOrs = users.join(' or ');
return new CommandOutput(
null,
`/vote ENTER THE GULAG. Chatters battling it out to not get ${muteString} ban. Vote KEEP not KICK!? ${userOrs} 30s`,
});

services.messageRelay.emit(
'poll',
JSON.stringify({
weighted: false,
time: pollDuration,
question: `ENTER THE GULAG. Chatters battling it out to not get a ${muteString} ban. Vote KEEP not KICK!?`,
options: users,
}),
);

return new CommandOutput(null, '');
};
}
module.exports = {
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/implementations/mutelinks.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function mutelinks(defaultPunishmentDuration) {
const listener = services.messageRelay.startListenerForChatMessages('mutelinks');

const formattedDuration = formatDuration(moment.duration(muteDuration, 'seconds'));
listener.on('message', (data) => {
listener.on('msg', (data) => {
const message = data.message.trim().toLowerCase();
if (state !== 'all' && !services.messageMatching.mentionsUser(message, mentionUser)) return;
if (!services.messageMatching.hasLink(message)) return;
Expand Down
117 changes: 65 additions & 52 deletions lib/commands/implementations/voteban.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,90 @@
const _ = require('lodash');
const moment = require('moment');

const _ = require('lodash');
const Command = require('../command-interface');
const CommandOutput = require('../command-output');
const { makeBan } = require('../../chat-utils/punishment-helpers');
const basePunishmentHelper = require('../base-punishment-helper');
const formatDuration = require('../../chat-utils/format-duration');

let voteBanStarted = false;
const weightedTranslateMap = {
flair8: 16,
flair3: 8,
flair1: 4,
flair13: 2,
flair9: 2,
};
function voteBan(ipBan, defaultBanTime, weighted) {
const pollDuration = 30000;

let failSafeTimeout = null;
let votebanActive = false;

return function ban(input, services, rawMessage) {
if (voteBanStarted) {
if (votebanActive) {
return new CommandOutput(
null,
'Vote ban in progress. Please wait for the current vote to finish.',
'Vote ban in progress. Please wait for the current vote ban to finish.',
);
}

const parsedInput = basePunishmentHelper(input, defaultBanTime)[0];

if (parsedInput === false) {
return new CommandOutput(
null,
'Could not parse the duration. Usage: "!voteban {amount}{m,h,d,w}OR{perm} {user}" !voteban 1d Destiny',
);
}

const { isPermanent, userToPunish, parsedDuration, parsedReason } = parsedInput;
const muteString = isPermanent
? 'PERMANENTLY'
: formatDuration(moment.duration(parsedDuration, 'seconds'));

voteBanStarted = true;
const listener = services.messageRelay.startListenerForChatMessages('voteban');
if (listener === false) {
return new CommandOutput(null, 'Something went wrong?? uhh. Restart me.');
}

const muteString = isPermanent
? 'PERMANENTLY'
: formatDuration(moment.duration(parsedDuration, 'seconds'));
const votedMap = {};
let yes = 0;
let no = 0;

listener.on('message', (data) => {
if (votedMap[data.user]) {
return;
}
const message = data.message.trim();
if (message.trim() === '1' || message.trim() === '2') {
let votes = 1;
if (weighted) {
votes = _.max(
Object.keys(weightedTranslateMap).map((k) => {
const idx = data.roles.indexOf(k);
if (idx === -1) return 1;
return weightedTranslateMap[k];
}),
);
}
votedMap[data.user] = true;
// eslint-disable-next-line no-unused-expressions
message.trim() === '1' ? (yes += votes) : (no += votes);
listener.on('err', (message) => {
const error = JSON.parse(message);
if (error.description === 'activepoll' && !votebanActive) {
clearTimeout(failSafeTimeout);
services.messageRelay.stopRelay('voteban');
services.messageRelay.sendOutputMessage(
'Poll in progress. Please wait for the current poll to finish.',
);
}
});

setTimeout(() => {
voteBanStarted = false;
listener.on('pollstart', () => {
votebanActive = true;
services.messageRelay.sendOutputMessage(
`Should we ban ${userToPunish} ${
muteString === 'PERMANENTLY' ? muteString : `for ${muteString}`
} ${parsedReason ? ` Reason: ${parsedReason}` : ''}?`,
);

// Fail-safe
failSafeTimeout = setTimeout(() => {
votebanActive = false;
services.messageRelay.stopRelay('voteban');
}, pollDuration + 5000);
});

listener.on('pollstop', (message) => {
clearTimeout(failSafeTimeout);
votebanActive = false;
services.messageRelay.stopRelay('voteban');

services.messageRelay.sendOutputMessage('Total votes:');
services.messageRelay.sendOutputMessage(`Yes votes: ${yes}`);
services.messageRelay.sendOutputMessage(`No votes: ${no}`);
if (yes <= no) {

const poll = JSON.parse(message);
const votes = _.zipObject(poll.options, poll.totals);

services.messageRelay.sendOutputMessage(`Yes votes: ${votes.yes}`);
services.messageRelay.sendOutputMessage(`No votes: ${votes.no}`);

if (votes.yes <= votes.no) {
services.messageRelay.sendOutputMessage(
`No votes win by ${no - yes} votes, ${userToPunish} is safe for now.. AYAYA `,
`No votes win by ${votes.no - votes.yes} votes, ${userToPunish} is safe for now.. AYAYA `,
);
return;
}

services.punishmentStream.write(
makeBan(
userToPunish,
Expand All @@ -87,17 +93,24 @@ function voteBan(ipBan, defaultBanTime, weighted) {
isPermanent,
`${userToPunish} banned through bot by a VOTE BAN started by ${rawMessage.user}. ${
parsedReason ? `Reason: ${parsedReason}` : ''
} Yes votes: ${yes} No Votes: ${no}`,
} Yes votes: ${votes.yes} No Votes: ${votes.no}`,
),
);
}, 30500);
});

return new CommandOutput(
null,
`/vote Should we ban ${userToPunish} ${
muteString === 'PERMANENTLY' ? muteString : `for ${muteString}`
} ${parsedReason ? ` Reason: ${parsedReason}` : ''}? yes or no 30s`,
services.messageRelay.emit(
'poll',
JSON.stringify({
weighted,
time: pollDuration,
question: `Should we ban ${userToPunish} ${
muteString === 'PERMANENTLY' ? muteString : `for ${muteString}`
} ${parsedReason ? ` Reason: ${parsedReason}` : ''}`,
options: ['yes', 'no'],
}),
);

return new CommandOutput(null, '');
};
}

Expand Down
Loading

0 comments on commit b816bf7

Please sign in to comment.