From c634c22ca9eaa03ac112c96202c3d61be5034964 Mon Sep 17 00:00:00 2001 From: Gavin Mogan Date: Fri, 6 Mar 2020 22:58:53 -0800 Subject: [PATCH] Script that generates meetup events --- make_meetups.js | 157 +++++++++++++++++++++++++++++++++++++++++++ make_meetups.test.js | 79 ++++++++++++++++++++++ package.json | 3 + 3 files changed, 239 insertions(+) create mode 100644 make_meetups.js create mode 100644 make_meetups.test.js diff --git a/make_meetups.js b/make_meetups.js new file mode 100644 index 00000000..0fd509b7 --- /dev/null +++ b/make_meetups.js @@ -0,0 +1,157 @@ +/* eslint-env node */ +const getTimezoneOffset = require(`get-timezone-offset`); +const request = require(`request`); + +const events = { + 'nodeschool': { + reference_event_id: `266012076`, + meetup_urlname: `nodeschool-vancouver`, + timezone: `America/Vancouver`, + heading: `💻 NodeSchool: %season% Is Here Series %emoji%`, + startTime: 12, + duration: 4 * 60 * 60 * 1000, // 4 hours in milliseconds + dayOfWeek: 6, // saturday + week: 2, // second week + ignoreMonths: [], + body: `Part of the %year% %season% Is Here Series %emoji% + +Cool! 🙂 Read on...the usual spiel follows. + +Are you a beginner at using Node.js and/or JavaScript? Are you wanting a refresher? Are you looking to level up your knowledge? + +We don't have set classes, and as such it is considered a self study program. The NodeSchool organization has a lot of workshops for you to learn from, and we help out along the way, but that doesn't mean you have to do the workshops, we are a diverse group of people learning and growing together. + +Bring your laptops and, if you can, have Node.js installed before you arrive. It's time for another session of learning! + +We have regular mentors to help everyone learn. But we can't ever have too many people who want to help others learn, right?! We promise that by the end of the session you'll know enough to help the person sitting next to you learn too 💪 + +RSVP "yes" and come learn and/or help others learn Node.js and/or JavaScript over a casual Saturday afternoon!`, + }, + // 'intro-to-open-source': { } +}; + +function getSeason(date) { + // December through February is Winter 🔥, + // March through May is Spring 🌻, + // June through August is Summer 🌦 + // September through November is Fall 🍁. + switch (date.getMonth()) { + case 11: // December + case 0: // january + case 1: // feb + return { season: `Winter`, emoji: `🔥` }; + case 2: // March + case 3: // April + case 4: // May + return { season: `Spring`, emoji: `🌻` }; + case 5: // June + case 6: // July + case 7: // August + return { season: `Summer`, emoji: `🌦` }; + case 8: // September + case 9: // October + case 10: // November + return { season: `Fall`, emoji: `🍁` }; + } + throw new Error(`somehow different`); +} + +function findDayOfWeek(year, month, desiredWeek, desiredDayOfWeek) { + let startingDate = new Date(year, month); + while (startingDate.getDay() != desiredDayOfWeek) { + startingDate.setDate(startingDate.getDate() + 1); + } + // should now be the first $day of the first week + if (desiredWeek == 1) { + return startingDate.getDate(); + } + + for (let i = 1; i < desiredWeek; i += 1) { + startingDate.setDate(startingDate.getDate() + 7); + } + return startingDate.getDate(); +} + +function getEventForMonth(type, year, month) { + if (events[type].ignoreMonths.includes(month)) { + return null; + } + + const day = findDayOfWeek(year, month, events[type].week, events[type].dayOfWeek); + const offset = getTimezoneOffset(events[type].timezone, new Date(Date.UTC(year, month, day))) * 60000; // convert to milliseconds + + const eventStart = new Date(Date.UTC(year, month, day, events[type].startTime) + offset); + const replacements = { + month, + year, + day, + ...getSeason(eventStart), + }; + + const replacer = function(str) { + if (!str) { return str; } + return str.trim().replace(/%(\w+)%/g, function(match, word) { + return replacements[word]; + }); + }; + + return { + time: eventStart.getTime(), + duration: events[type].duration, + name: replacer(events[type].heading), + description: replacer(events[type].body), + }; +} + +const requestPromiseGet = (url) => { + return new Promise(function(resolve, reject) { + request.get(url, (error, response, body) => { + if (error) { + reject(error); + return; + } + resolve(JSON.parse(body)); + }); + }); +}; + +async function popuplateMissingEvents(year, type) { + const event = events[type]; + if (!event) { throw new Error(`unknown type: ${type}`); } + + const referenceEvent = await requestPromiseGet(`https://api.meetup.com/${event.meetup_urlname}/events/${event.reference_event_id}/?fields=description_images,featured_photo`); + + const yearlyEvents = await requestPromiseGet(`https://api.meetup.com/${event.meetup_urlname}/events?no_earlier_than=${year}-01-01T00:00:00.000&page=50&status=past,upcoming`).then(events => { + return events.reduce(function(all, event) { + all[new Date(event.time).getMonth()] = event; + return all; + }, {}); + }); + + const eventsToCreate = []; + for (let month = 0; month < 12; month += 1) { + if (yearlyEvents[month]) { + continue; // fixme multiple event types per month + } + const data = { + featured_photo_id: referenceEvent.featured_photo.id, + rsvp_limit: referenceEvent.rsvp_limit, + ...getEventForMonth(type, year, month), + }; + if (!data.time) { + continue; // no event this month + } + eventsToCreate.push(data); + } + return eventsToCreate; +} + +if (require.main === module) { + popuplateMissingEvents(2020, `nodeschool`).then(console.log, console.error); +} + +module.exports = { + getSeason, + findDayOfWeek, + getEventForMonth, +}; diff --git a/make_meetups.test.js b/make_meetups.test.js new file mode 100644 index 00000000..00817f1d --- /dev/null +++ b/make_meetups.test.js @@ -0,0 +1,79 @@ +/* eslint-env mocha */ +/* eslint-disable jest/expect-expect */ +const { getSeason, findDayOfWeek, getEventForMonth } = require(`./make_meetups.js`); + +const assert = require(`assert`); + +const dates = [ + { + date: new Date(`April 13, 2019 16:00:00`), + season: `Spring`, + }, + { + date: new Date(`May 11, 2019 16:00:00`), + season: `Spring`, // actual meetup is wrong :) + }, + { + date: new Date(`June 8, 2019 16:00:00`), + season: `Summer`, + }, + { + date: new Date(`July 13, 2019 16:00:00`), + season: `Summer`, + }, + { + date: new Date(`August 10, 2019 16:00:00`), + season: `Summer`, + }, + { + date: new Date(`Sept 14, 2019 16:00:00`), + season: `Fall`, + }, + { + date: new Date(`Nov 9, 2019 16:00:00`), + season: `Fall`, + }, + { + date: new Date(`Dec 14, 2019 16:00:00`), + season: `Winter`, + }, + { + date: new Date(`Jan 11, 2020 16:00:00`), + season: `Winter`, + }, + { + date: new Date(`Feb 8, 2020 16:00:00`), + season: `Winter`, + }, + { + date: new Date(`Mar 14, 2020 16:00:00`), + season: `Spring`, + }, +]; + +describe(`make_meetups`, function() { + for (const date of dates) { + it(`getSeason - ${date.date}`, function () { + assert.deepEqual(getSeason(date.date).season, date.season); + }); + it(`findDayOfWeek - ${date.date}`, function () { + assert.deepEqual(findDayOfWeek( + date.date.getYear() + 1900, + date.date.getMonth(), + 2, + 6, + ), date.date.getDate()); + }); + } + it(`getEventForMonth`, function() { + assert.deepEqual( + getEventForMonth(`nodeschool`, 2020, 2 /* March */), + { + "body": `Part of the **2020 Spring** Is Here Series **🌻**\n\nCool! 🙂 Read on...the usual spiel follows.\n\nAre you a beginner at using Node.js and/or JavaScript? Are you wanting a refresher? Are you looking to level up your knowledge?\n\nWe don't have set classes, and as such it is considered a self study program. The NodeSchool organization has a lot of workshops for you to learn from, and we help out along the way, but that doesn't mean you have to do the workshops, we are a diverse group of people learning and growing together.\n\nBring your laptops and, if you can, have Node.js installed before you arrive. It's time for another session of learning!\n\nWe have regular mentors to help everyone learn. But we can't ever have too many people who want to help others learn, right?! We promise that by the end of the session you'll know enough to help the person sitting next to you learn too 💪\n\nRSVP "yes" and come learn and/or help others learn Node.js and/or JavaScript over a casual Saturday afternoon!`, + "duration": 14400000, + "eventStart": new Date(1584212400000), // taken from existing meetup id + "title": `💻 NodeSchool: Spring Is Here Series 🌻`, + }, + ); + }); +}); diff --git a/package.json b/package.json index 4d002cb2..e2ddfc67 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "gatsby-transformer-remark": "^2.6.52", "gatsby-transformer-sharp": "^2.3.14", "gatsby-transformer-yaml": "^2.2.25", + "mocha": "^7.1.0", "node-sass": "^4.13.1", "prismjs": "^1.19.0", "prop-types": "^15.7.2", @@ -47,7 +48,9 @@ "eslint-plugin-babel": "^5.3.0", "eslint-plugin-jest": "^23.7.0", "eslint-plugin-promise": "^4.2.1", + "get-timezone-offset": "^1.0.3", "gh-pages": "^2.2.0", + "meetup-api": "^1.4.38", "npm-run-all": "^4.1.5", "prettier": "^1.19.1", "prettier-eslint-cli": "^5.0.0"