educ-bot/index.js

246 lines
7.8 KiB
JavaScript
Raw Normal View History

2020-03-31 13:02:48 +00:00
/* Run dotenv */
require('dotenv').config();
const fs = require('fs');
2020-03-24 15:01:15 +00:00
2020-04-02 16:01:29 +00:00
/* Catch evry unhandled promise rejection */
process.on('unhandledRejection', error => console.error('Uncaught Promise Rejection', error));
2020-03-31 13:02:48 +00:00
/* Deep clone of objects */
const clonedeep = require('lodash.clonedeep')
2020-03-24 15:01:15 +00:00
2020-03-31 13:02:48 +00:00
/* Generate random string for token */
const randomstring = require("randomstring");
/* Liste des réactions possibles par défaut et de leurs représentation actuelle */
const defaultReactions = JSON.parse(fs.readFileSync('defaultReactions.json', 'utf8'));
/* The html page will render data passed in WS */
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: process.env.WS_PORT })
wss.on('connection', ws => {
ws.isAlive = true;
ws.on('pong', heartbeat);
ws.on('message', message => {
const data = JSON.parse(message)
if (!('channel' in data && 'action' in data && 'web_token' in data)) {
ws.send('{"error":"invalid request"}')
return
}
else if (!(data['action'] in wsActions)) {
ws.send('{"error":"bad action"}')
return
}
else if (!(data['channel'] in channels && channels[data['channel']].web_token === data['web_token'])) {
ws.send('{"error": "bad channel"}')
return
}
else {
wsActions[data['action']](data, channels[data['channel']], ws)
}
})
})
function heartbeat() {
this.isAlive = true;
}
const interval = setInterval(function ping() {
wss.clients.forEach(function (ws) {
if (ws.isAlive === false) return ws.terminate();
ws.isAlive = false;
ws.ping(()=>{});
});
}, 30000);
wss.on('close', function close() {
clearInterval(interval);
});
// TODO penser à prévenir le web quand un type de réaction est ajoutée/supprimée
const wsActions = {
'init': wsInit,
'add_reaction': wsAddReaction,
'remove': wsRemoveReaction,
'reset': wsReset,
}
function wsInit (data, channel, ws) {
channel.ws_clients.push(ws)
2020-03-31 18:59:36 +00:00
wsSendState(channel, ws)
}
function wsSendState(channel, ws) {
2020-03-31 13:02:48 +00:00
ws.send(JSON.stringify(channel.reactions))
2020-03-30 18:55:12 +00:00
}
2020-03-31 18:59:36 +00:00
function wsSendStateAll(channel) {
for (var index in channel.ws_clients) {
wsSendState(channel, channel.ws_clients[index])
}
}
2020-03-31 13:02:48 +00:00
function wsAddReaction (data, channel, ws) {
if (!('reaction' in data)) {
ws.send('{"error":"No reaction supplied", "action":"add"}')
}
}
function wsRemoveReaction (data, channel, ws) {
if (!('reaction' in data)) {
ws.send('{"error":"No reaction supplied", "action":"add"}')
}
}
function wsReset (data, channel, ws) {
}
2020-03-30 18:55:12 +00:00
/* Liste des channels où on peut lire avec le dernier message que lon y a envoyé */
var channels = {}
2020-03-31 13:02:48 +00:00
function educpopReset (channel) {
for (var index in channel.reactions) {
channel.reactions[index].people = []
}
}
2020-03-30 18:55:12 +00:00
2020-03-31 13:02:48 +00:00
function educpopAddChannel (discordChannel) {
channels [discordChannel.id] = {
'last_msg': null, /* On se souvient du dernier post que ce bot a envoyé pour le virer dès que possible */
'discord_channel': discordChannel,
'ws_clients': [],
'web_token': randomstring.generate(), /* web auth */
'reactions': Object.assign({}, clonedeep(defaultReactions)),
'pause': false,
}
educpopReset(channels[discordChannel.id])
}
2020-03-24 15:01:15 +00:00
2020-03-31 13:02:48 +00:00
function educpopDelChannel (channel) {
delete channels[channel.discord_channel.id]
}
function educpopPause (channel) {
channel.pause = true
}
// TODO wait for database before using this
function educpopAddReaction (channel, word, prefix, description) {
channels[channelId].reactions[word] = {'prefix': prefix, 'description': description, 'people':[]}
}
function educpopDelReaction (channelId, word) {
delete channels[channelId].reactions[word]
}
function educpopAddPerson (channel, username, reaction) {
var liste = channel.reactions[reaction].people
if (liste.indexOf(username) < 0) {
liste.push(username)
2020-03-24 15:01:15 +00:00
}
2020-03-31 13:02:48 +00:00
}
function educpopDelPerson (channel, username, reaction) {
var liste = channel.reactions[reaction].people
var index = liste.indexOf(username)
if (index >= 0) {
liste.splice(index, 1)
}
}
/* Connexion à discord */
const Discord = require('discord.js');
const client = new Discord.Client();
client.on('ready', () => {
console.log('Connected to Discord as ' + client.user.tag);
client.user.setAvatar('avatar.png')
2020-04-02 17:44:09 +00:00
client.user.setUsername(process.env.BOT_USERNAME)
2020-03-31 13:02:48 +00:00
});
/* Discord message center */
client.on('message', msg => {
2020-04-02 16:01:29 +00:00
//TODO
//const prefixRegex = new RegExp(`^(<@!?${client.user.id}>|${escapeRegex(prefix)})\\s*`);
//if (!prefixRegex.test(message.content)) return;
2020-03-31 13:02:48 +00:00
if (msg.content === '!educpop-enable') {
if (msg.channel.id in channels) {
2020-03-30 18:55:12 +00:00
msg.reply('Jécoute déjà ce canal texte.')
} else {
2020-03-31 13:02:48 +00:00
educpopAddChannel(msg.channel)
2020-03-30 18:55:12 +00:00
msg.reply('Jécoute maintenant ce canal texte.')
}
2020-03-31 13:02:48 +00:00
return
2020-03-24 15:01:15 +00:00
}
2020-03-31 13:02:48 +00:00
if (msg.content === '!educpop-disable') {
2020-03-30 18:55:12 +00:00
var id = msg.channel.id
if (id in channels) {
2020-03-31 13:02:48 +00:00
educpopDelChannel(id)
2020-03-30 18:55:12 +00:00
msg.reply('Je nécoute plus ce canal texte.')
} else {
msg.reply('Je nécoutais pas ce canal texte :o')
}
2020-03-31 13:02:48 +00:00
return
}
if (msg.content === '!educpop-help') {
msg.reply('Voilà comment mutiliser. Taper :\n!educpop-enable pour activer le bot sur ce salon ;\n!educpop-disable pour le désactiver ;\n!educpop-list pour voir la liste des réactions possibles ;\n!educpop-reset pour remettre les compteurs à zéro.')
return
}
/* Listen only to enabled channels */
if(!(msg.channel.id in channels)) { return }
var channel = channels[msg.channel.id]
var reactions = channel.reactions
if(msg.content === '!educpop-reset') {
educpopReset
reply(channel)
2020-03-31 18:59:36 +00:00
}
else if (msg.content === '!educpop-list') {
2020-03-31 13:02:48 +00:00
var text = 'Tapez simplement le mot-clé ci-dessous pour être comptabilisé. Tapez un - immédiatement suivi du mot-clé pour être retiré du compte : -oui par exemple !'
2020-03-30 18:55:12 +00:00
for (var index in reactions) {
text += '\n' + reactions[index].prefix + index + ' : ' + reactions[index].description
}
2020-03-31 13:02:48 +00:00
msg.reply(text)
2020-03-24 15:01:15 +00:00
}
2020-03-31 18:59:36 +00:00
else if (msg.content === '!educpop-web') {
2020-04-02 16:33:21 +00:00
msg.reply('https://educbot.jean-cloud.net?channel_id=' + msg.channel.id + '&web_token=' + channel.web_token)
2020-03-31 18:59:36 +00:00
}
2020-03-30 18:55:12 +00:00
/* save and ignore own messages */
2020-03-31 13:02:48 +00:00
else if(msg.author.username === process.env.BOT_USERNAME){
2020-04-02 17:44:09 +00:00
if (!msg.content.startsWith('<')) /* Save if its educpop summary */
2020-03-31 13:02:48 +00:00
channel.last_msg = msg;
2020-03-24 15:01:15 +00:00
}
2020-03-30 18:55:12 +00:00
/* Educ pop stuff */
else if(msg.content.startsWith('-')) {
2020-03-31 13:02:48 +00:00
const content = msg.content.slice(1)
2020-03-31 08:54:11 +00:00
if (content.toLowerCase() in reactions) {
2020-04-02 17:44:09 +00:00
educpopDelPerson(channel, msg.member.nickname, content.toLowerCase())
2020-03-31 13:02:48 +00:00
msg.delete()
reply(channel)
2020-03-30 18:55:12 +00:00
}
2020-03-24 15:01:15 +00:00
}
2020-03-31 08:54:11 +00:00
else if (msg.content.toLowerCase() in reactions) {
2020-03-31 13:02:48 +00:00
var reaction = msg.content.toLowerCase()
2020-04-02 17:44:09 +00:00
educpopAddPerson(channel, msg.member.nickname, msg.content.toLowerCase())
2020-03-31 13:02:48 +00:00
msg.delete()
reply(channel)
2020-03-30 18:55:12 +00:00
}
});
2020-03-24 15:01:15 +00:00
2020-03-31 13:02:48 +00:00
/* Recap educ-pop state on discord. Delete action message and last educ-pop recap */
2020-03-31 18:59:36 +00:00
/* This function refresh the display */
2020-03-31 13:02:48 +00:00
function reply (channel) {
2020-03-30 18:55:12 +00:00
var text = ''
2020-03-31 13:02:48 +00:00
for (var index in channel.reactions) {
if (channel.reactions[index].people.length > 0)
text += '\n' + channel.reactions[index].prefix + String(channel.reactions[index].people)
2020-03-30 18:55:12 +00:00
}
2020-03-31 08:54:11 +00:00
if (text === '') {
text = 'Personne ne sest manifesté :/'
}
2020-03-31 13:02:48 +00:00
if(channel.last_msg) channel.last_msg.delete()
channel.discord_channel.send(text)
2020-03-31 18:59:36 +00:00
wsSendStateAll(channel)
2020-03-30 18:55:12 +00:00
}
2020-03-24 15:01:15 +00:00
2020-03-31 13:02:48 +00:00
/* Actual discord login */
client.login(process.env.DISCORD_TOKEN);