diff --git a/commands/dev only/backupBot.js b/commands/dev only/backupBot.js index 0850534..ee91038 100644 --- a/commands/dev only/backupBot.js +++ b/commands/dev only/backupBot.js @@ -1,5 +1,5 @@ const fs = require('fs'); -const {Buffer} = require('buffer'); +const { Client } = require('discord.js'); function mapToObj(map){ const obj = {} @@ -43,7 +43,10 @@ async function backupLists(bot, IDM) { } } - +/** + * @param {Client} bot + * @param {Boolean} IDM + */ async function loadBotBackups(bot, IDM) { try { if (IDM) { @@ -52,6 +55,8 @@ async function loadBotBackups(bot, IDM) { } else { bot.lockedChannels = objToMap(JSON.parse(botBackups.locked)); } + + // bot.user.setActivity("RESTARTING BOT, PLEASE STAND BY.mp3", { type: "LISTENING" }); // User is....undefined???? } catch (err) { console.error(err); bot.lockedChannels = new Map(); diff --git a/commands/premium/icsToEvents.js b/commands/premium/icsToEvents.js new file mode 100644 index 0000000..ef62631 --- /dev/null +++ b/commands/premium/icsToEvents.js @@ -0,0 +1,250 @@ +const { ICalParser } = require('cozy-ical'); +const { URL } = require('url'); +const { Constants } = require('discord.js'); +const request = require('request'); +const { verPremium } = require('../premium/verifyPremium.js'); + + +//#region SET REMINDERS + +function addReminder(interaction, bot, obj, Id) { + return new Promise((resolve, reject) => { + try { + bot.mongoconnection.then((client) => { + // Update the Key object first to check if the time is already there + const kbo = client.db('main').collection('reminderKeys'); + kbo.findOne(({ 'userId': Id })).then((doc) => { + const t = obj.time.toString(); + try { + if (doc.times.indexOf(obj.time) == -1) { + kbo.updateOne({ 'userId': Id }, { $push: { times: t } }) + } else { + //Event already exists at this time + reject("An event already exists at this time!"); + return; // interaction.channel.send("An event already exists at this time!"); + } + + //Update the Time object + const dbo = client.db('main').collection('reminders'); + dbo.findOne({ time: t }).then((doc) => { + let n = 0; + if (doc) { + n = doc.amt; + doc.amt ++; + + doc[`${n}`] = obj.event; + dbo.findOneAndReplace({ time: t }, doc); + } else { + const d = new Date(Number(obj.time)); + doc = { "0": obj.event, "time": t, "month": d.getMonth(), "amt": 1 }; //Month used for clearing when the calendar month begins (maybe modify the garbage collection with an `else if (day == 1? clear last month)` ) + dbo.insertOne(doc); + } + + //Reply with the reminder in correct format + // interaction.reply({ content: "REMINDER SAVED!", embeds: [embd], ephemeral: true }); + resolve(true); + }).catch((err) => { + console.error(err); + // interaction.reply("Uh Oh! An error has occured!"); + }); + } catch (err) { + console.error(err); //interaction.reply("Uh Oh! An error has occured!"); + reject(err); + } + }).catch((err) => { + console.log("ERR"); + console.error(err); + reject(false); + // interaction.reply("Uh Oh! An error has occured!"); + }); + }); + } catch (err) { + console.error(err); + // return interaction.reply("Uh Oh! An error has occured!"); // Gets "acknowledged" too many times + } + }); +} + +//#endregion + + + +//#region SETUP AND PARSING +function isValidUrl(s) { + try { + new URL(s); + return true; + } catch (err) { + return false; + } +}; + + +class calClass { + constructor(vevent) { + const model = vevent.model; + const alarms = vevent.subComponents; + + if (alarms && alarms[0] && alarms[0].model) { + let temp = alarms[0].model.trigger; + temp = temp.split('DT')[1]; + temp = temp.split("H"); + + let hours = (temp[0] && temp[0] != '0') ? Number(temp[0]) : 0; + let minutesStr = temp[1].split('M')[0]; + let minutes = (minutesStr && !isNaN(minutesStr)) ? hours + Number(minutesStr) : hours; + + this.offset = minutes; + } else { + this.offset = 0; + } + + this.name = model.summary; + this.description = (model.description) ? model.description : "N/A"; + + const dateTime = new Date(model.startDate); + this.time = dateTime.getTime()/1000; + + if (isValidUrl(model.location)) { + this.url = model.location || undefined; + this.loc = undefined; + } else { + this.url = undefined; + this.loc = model.location || undefined; + } + } + + isValidUrl(s) { + try { + new URL(s); + return true; + } catch (err) { + return false; + } + } + + exportAsObj(gid, uid) { + const obj = { time: this.time, event: { guildId: gid, userId: uid, name: this.name, description: this.description, offset: this.offset, link: this.url, location: this.loc } } + return obj; + } +} + + +function parseData(calStr, gid, uid) { + return new Promise((resolve, reject) => { + const parser = new ICalParser(); + parser.parseString(calStr, function(err, cal) { + try { + const arr = []; + + for (i in cal.subComponents) { + const a = new calClass(cal.subComponents[i]); + arr.push(a.exportAsObj(gid, uid)); + } + + resolve(arr); + } catch (err) { + console.log(err); + reject(err); + } + }); + }); +} + + +/** + * @param {String} fileName + */ +function readFileAndParse(url, bot, interaction, gid, uid) { + request.get(url, function (error, response, body) { + try { + if (!error && response.statusCode == 200) { + const isGuild = (gid && !uid) || false; + const notAdded = []; + + const Id = (isGuild) ? gid : uid; + + parseData(body, gid, uid).then((arr) => { + + new Promise((resolve, reject) => { + // If the key does not exist, create it + if (arr.length > 0) { + bot.mongoconnection.then((client) => { + const kbo = client.db('main').collection('reminderKeys'); + kbo.findOne(({ 'userId': Id })).then((doc) => { + if (!doc) { + doc = { userId: Id, times: [] } + kbo.insertOne(doc); + + reject("New user created, please try again!"); + } else { + resolve(true); + } + }); + }); + } else { + reject("No data..."); + } + + // const m = new Map(arr.map((obj, ind) => { return [ind, obj]; })); + }).then(() => { + Promise.all(arr.map((obj, ind) => { + addReminder(interaction, bot, obj, Id).then(() => {}) + .catch((err) => { + notAdded.push(err); + }); + })).then((t) => { + const r1 = { content: `ITEMS NOT ADDED:\n${notAdded.join("\n")}`, ephemeral: true } + + if (r1.content != "ITEMS NOT ADDED:\n") { + interaction.reply(r1).catch((err) => { interaction.channel.send(r1); }); + } else { + const r2 = `All ${arr.length} items added to calendar!`; + interaction.reply(r2).catch((err) => { interaction.channel.send(r2); }); + } + }); + }).catch((err) => { + interaction.reply(err); + }) + }).catch((err) => { + console.log(err); + }); + } + } catch (err) { + console.log(err); + interaction.reply({ content: "Uh oh, there's been an error!", ephemeral: true}); + } + }); +} + +//#endregion + + +module.exports = { + name: 'import_ics', + description: 'Import events using a calendar', + async execute(interaction, Discord, Client, bot) { + //Check if the user has premium + await verPremium(bot, interaction.user.id).then(() => { + const url = interaction.options.data[0].attachment.attachment; + + if (!url.endsWith(".ics")) { + return interaction.reply("Please use a valid ***.ics*** file!") + } + + let uid, gid; + if (interaction.channel.type == 'DM') { + uid = interaction.user.id; + } else { + gid = interaction.guildId; + } + readFileAndParse(url, bot, interaction, gid, uid); + }).catch(() => { + interaction.reply("You have to be a premium subscriber to use this feature!"); + }); + }, + options: [ + {name: 'ics_file', description: 'The ics file to input', type: Constants.ApplicationCommandOptionTypes.ATTACHMENT, required: true}, + ], + isDm: true +} \ No newline at end of file diff --git a/commands/premium/reminders.js b/commands/premium/reminders.js index 0ce644e..84403fb 100644 --- a/commands/premium/reminders.js +++ b/commands/premium/reminders.js @@ -190,57 +190,78 @@ function addEvent(obj, connection, interaction, embd) { } } +/** + * @returns { Promise<[]> | Promise<[false, []] | [true, String]>} (all events) || (custom err) ? [true, err] : [false, err] + */ +function getEvents(bot, interaction, id, jpage = 0, isGuild = false, refered = false, isExport = false) { + return new Promise((resolve, reject) => { + var userId = false; + var guildId = false; + const numperpage = 5; -function getEvents(bot, interaction, id, jpage = 0, isGuild = false, refered = false) { - var userId = false; - var guildId = false; - const numperpage = 5; + if (isGuild) { + guildId = id; + } else { + userId = id; + } - if (isGuild) { - guildId = id; - } else { - userId = id; - } + bot.mongoconnection.then((client) => { + try { + var times; + const dbo = client.db('main').collection('reminderKeys'); - bot.mongoconnection.then((client) => { - try { - var times; - const dbo = client.db('main').collection('reminderKeys'); - - //ReminderKeys are all stored as userId, the reminders themselves are not - dbo.findOne({$or: [ {userId: userId}, {userId: guildId} ]}).then((doc) => { - if (!doc) { return interaction.reply("No events exist!"); } - times = doc.times; - const tbo = client.db('main').collection('reminders'); - - tbo.find({time: {$in: times}}).toArray((err, docs) => { - //There's gotta be a better way - var temp = [""]; - var page = 0; - - for (let i = 0; i < docs.length; i ++) { - if (i != 0 && i % numperpage == 0) { - page ++; - temp[page] = ''; - } - // temp += `__***Events On ${new Date(Number(docs[i].time))}***__\n\n`; - for (let j in docs[i]) { - if (!isNaN(j) && (docs[i][j].userId == userId || docs[i][j].guildId == guildId)) { - const obj = docs[i][j]; - temp[page] += `Name: ${obj.name}\nDescription: ${obj.description}\nDate/Time: ${new Date(Number(docs[i].time))}\nOffset: ${obj.offset}\nLink: ${obj.link}\nLocation: ${obj.location}\n------------------------------\n` - } + //ReminderKeys are all stored as userId, the reminders themselves are not + dbo.findOne({$or: [ {userId: userId}, {userId: guildId} ]}).then((doc) => { + if (!doc) { + if (isExport) { + return reject([true, "No events exist!"]); } + + return interaction.reply("No events exist!"); } - //Create the embed - postEmbd(bot, temp, interaction, jpage, isGuild, id, refered); + times = doc.times; + const tbo = client.db('main').collection('reminders'); + + tbo.find({time: {$in: times}}).toArray((err, docs) => { + + if (isExport) { + return resolve(docs); + } + + //There's gotta be a better way + var temp = [""]; + var page = 0; + + for (let i = 0; i < docs.length; i ++) { + if (i != 0 && i % numperpage == 0) { + page ++; + temp[page] = ''; + } + // temp += `__***Events On ${new Date(Number(docs[i].time))}***__\n\n`; + for (let j in docs[i]) { + if (!isNaN(j) && (docs[i][j].userId == userId || docs[i][j].guildId == guildId)) { + const obj = docs[i][j]; + temp[page] += `Name: ${obj.name}\nDescription: ${obj.description}\nDate/Time: ${new Date(Number(docs[i].time))}\nOffset: ${obj.offset}\nLink: ${obj.link}\nLocation: ${obj.location}\n------------------------------\n` + } + } + } + + //Create the embed + postEmbd(bot, temp, interaction, jpage, isGuild, id, refered); + + resolve(true); + }); }); - }); - } catch (err) { - console.log(err); - return interaction.reply("Uh Oh! There's been an error!"); - } - }); + } catch (err) { + console.log(err); + if (isExport) { + return reject([false, err]); + } + return interaction.reply("Uh Oh! There's been an error!"); + } + }); + }); } //#endregion @@ -410,6 +431,6 @@ module.exports = { } }); }); - }, modalHandle, turnPage, + }, modalHandle, turnPage, addEvent, getEvents, options: [] } \ No newline at end of file