From 937f2712afc6451af862f63c4d38b7f931c51122 Mon Sep 17 00:00:00 2001 From: Dragon Fire Date: Wed, 2 Dec 2020 09:44:13 -0500 Subject: [PATCH] Calendar Command --- README.md | 7 +-- commands/events/calendar.js | 85 ++++++++++++++++++------------------- commands/events/holidays.js | 62 +++++++++++++++++++++++++++ package.json | 2 +- 4 files changed, 109 insertions(+), 47 deletions(-) create mode 100644 commands/events/holidays.js diff --git a/README.md b/README.md index c7a55724..91f07025 100644 --- a/README.md +++ b/README.md @@ -257,7 +257,7 @@ in the appropriate channel's topic to use it. ## Commands -Total: 565 +Total: 566 ### Utility: @@ -438,13 +438,14 @@ Total: 565 * **anime-airing:** Responds with a list of the anime that air today. * **apod:** Responds with today's Astronomy Picture of the Day. -* **calendar:** Responds with today's holidays. +* **calendar:** Responds with the calendar for a specific month and year. * **covid-19:** Responds with stats for COVID-19. * **days-since:** Responds with how many days there have been since a certain date. * **days-until:** Responds with how many days there are until a certain date. * **doomsday-clock:** Responds with the current time of the Doomsday Clock. * **friday-the-13th:** Determines if today is Friday the 13th. * **google-doodle:** Responds with a Google Doodle, either the latest one or a random one from the past. +* **holidays:** Responds with today's holidays. * **horoscope:** Responds with today's horoscope for a specific Zodiac sign. * **humble-bundle:** Responds with the current Humble Bundle. * **is-tuesday:** Determines if today is Tuesday. @@ -1153,7 +1154,6 @@ here. - [Google](https://www.google.com/) * boardroom-meeting ([Noto Font](https://www.google.com/get/noto/)) * book ([Books API](https://developers.google.com/books/)) - * calendar ([Calendar API](https://developers.google.com/calendar/)) * catch ([Noto Font](https://www.google.com/get/noto/)) * caution ([Noto Font](https://www.google.com/get/noto/)) * change-my-mind ([Noto Font](https://www.google.com/get/noto/)) @@ -1169,6 +1169,7 @@ here. * google-doodle ([Google Doodles API](https://www.google.com/doodles)) * google-feud (Autofill API) * gru-plan ([Noto Font](https://www.google.com/get/noto/)) + * holidays ([Calendar API](https://developers.google.com/calendar/)) * if-those-kids-could-read ([Noto Font](https://www.google.com/get/noto/)) * lisa-presentation ([Noto Font](https://www.google.com/get/noto/)) * map ([Maps Static API](https://developers.google.com/maps/documentation/maps-static/intro)) diff --git a/commands/events/calendar.js b/commands/events/calendar.js index 3ea396a9..a459dc95 100644 --- a/commands/events/calendar.js +++ b/commands/events/calendar.js @@ -1,62 +1,61 @@ const Command = require('../../structures/Command'); -const request = require('node-superfetch'); -const { list, today, tomorrow } = require('../../util/Util'); -const { GOOGLE_KEY, GOOGLE_CALENDAR_ID, PERSONAL_GOOGLE_CALENDAR_ID } = process.env; +const { stripIndents } = require('common-tags'); +const { firstUpperCase } = require('../../util/Util'); +const monthsWith30 = [4, 6, 9, 11]; +const months = require('../../assets/json/month'); module.exports = class CalendarCommand extends Command { constructor(client) { super(client, { name: 'calendar', - aliases: ['holidays', 'events'], + aliases: ['cal'], group: 'events', memberName: 'calendar', - description: 'Responds with today\'s holidays.', - credit: [ + description: 'Responds with the calendar for a specific month and year.', + args: [ { - name: 'Google', - url: 'https://www.google.com/', - reason: 'Calendar API', - reasonURL: 'https://developers.google.com/calendar/' + key: 'month', + prompt: 'What month would you like to get the calendar of?', + type: 'month' + }, + { + key: 'year', + prompt: 'What year would you like to get the calendar of?', + type: 'integer', + min: 1 } ] }); } - async run(msg) { - try { - const events = []; - const standardEvents = await this.fetchHolidays(GOOGLE_CALENDAR_ID); - if (standardEvents) events.push(...standardEvents); - if (PERSONAL_GOOGLE_CALENDAR_ID) { - const personalEvents = await this.fetchHolidays(PERSONAL_GOOGLE_CALENDAR_ID); - if (personalEvents) events.push(...personalEvents); - } - if (!events.length) return msg.say('There are no holidays today...'); - const holidays = list(events.map(event => `**${event}**`)); - return msg.say(`Today${events.length === 1 ? ' is' : `'s holidays are`} ${holidays}!`); - } catch (err) { - return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); + run(msg, { month, year }) { + let display = stripIndents` + ${firstUpperCase(months[month - 1])} ${year} + ------------------------------------ + | Su | Mo | Tu | We | Th | Fr | Sa | + ------------------------------------ + `; + display += '\n'; + const startDay = new Date(`${month}/1/${year}`).getDay(); + for (let i = 0; i < startDay; i++) { + display += ' '; } + const daysInMonth = month === 2 ? this.isLeap(year) ? 29 : 28 : monthsWith30.includes(month) ? 30 : 31; + let currentDay = startDay; + for (let i = 0; i < daysInMonth; i++) { + display += `| ${(i + 1).toString().padStart(2, '0')} `; + if (currentDay === 6) { + display += '|\n------------------------------------\n'; + currentDay = 0; + } else { + currentDay += 1; + } + } + display += '|'; + return msg.code(null, display); } - async fetchHolidays(id) { - try { - const { body } = await request - .get(`https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(id)}/events`) - .query({ - maxResults: 20, - orderBy: 'startTime', - singleEvents: true, - timeMax: tomorrow().toISOString(), - timeMin: today().toISOString(), - timeZone: 'UTC', - key: GOOGLE_KEY - }); - if (!body.items.length) return null; - return body.items.map(holiday => holiday.summary); - } catch (err) { - if (err.status === 404) return null; - throw err; - } + isLeap(year) { + return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); } }; diff --git a/commands/events/holidays.js b/commands/events/holidays.js new file mode 100644 index 00000000..43eef3cd --- /dev/null +++ b/commands/events/holidays.js @@ -0,0 +1,62 @@ +const Command = require('../../structures/Command'); +const request = require('node-superfetch'); +const { list, today, tomorrow } = require('../../util/Util'); +const { GOOGLE_KEY, GOOGLE_CALENDAR_ID, PERSONAL_GOOGLE_CALENDAR_ID } = process.env; + +module.exports = class HolidaysCommand extends Command { + constructor(client) { + super(client, { + name: 'holidays', + aliases: ['events', 'google-calendar'], + group: 'events', + memberName: 'holidays', + description: 'Responds with today\'s holidays.', + credit: [ + { + name: 'Google', + url: 'https://www.google.com/', + reason: 'Calendar API', + reasonURL: 'https://developers.google.com/calendar/' + } + ] + }); + } + + async run(msg) { + try { + const events = []; + const standardEvents = await this.fetchHolidays(GOOGLE_CALENDAR_ID); + if (standardEvents) events.push(...standardEvents); + if (PERSONAL_GOOGLE_CALENDAR_ID) { + const personalEvents = await this.fetchHolidays(PERSONAL_GOOGLE_CALENDAR_ID); + if (personalEvents) events.push(...personalEvents); + } + if (!events.length) return msg.say('There are no holidays today...'); + const holidays = list(events.map(event => `**${event}**`)); + return msg.say(`Today${events.length === 1 ? ' is' : `'s holidays are`} ${holidays}!`); + } catch (err) { + return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); + } + } + + async fetchHolidays(id) { + try { + const { body } = await request + .get(`https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(id)}/events`) + .query({ + maxResults: 20, + orderBy: 'startTime', + singleEvents: true, + timeMax: tomorrow().toISOString(), + timeMin: today().toISOString(), + timeZone: 'UTC', + key: GOOGLE_KEY + }); + if (!body.items.length) return null; + return body.items.map(holiday => holiday.summary); + } catch (err) { + if (err.status === 404) return null; + throw err; + } + } +}; diff --git a/package.json b/package.json index b0ac8c52..bb9fc4e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xiao", - "version": "123.0.5", + "version": "123.1.0", "description": "Your personal server companion.", "main": "Xiao.js", "scripts": {