Birthday Bot! 🎂

This past weekend, I used Pipedream to build my first integration. Wow, what a cool experience.

The other day, I realized the HR Platform my company uses (BambooHR) had a nice feature for a Calendar RSS feed of birthdays. I’m sure you could go paste this into a nice tool somewhere, but essentially, what they actually gave you was a public link that pointed to an .ical file (standard calendar format) of everyone’s birthday at my company.

That got me thinking :bulb:

Below, I’ll be showing you exactly how I built Scale AI’s BirthdayBot.

Step by Step Guide:

Setting up the Workflow

I set up a Pipedream Workflow based on a Schedule, so it would run every morning:

The action this triggers is a custom node.js action.

The Action

Importing our helpers
First things first, I had to import a few NPM packages to help me handle some of the logistics.

const request = require("request");
const rp = require("request-promise");
const ical = require('node-ical');

request-promise is the async/await version of the popular request library in Node. Technically, it’s deprecated now and requires you to explicitly import the request library… but still works pretty darn fine for this use case.

node-ical is a nice little parser for working with .ical files so I don’t need to do a bunch of parsing logic myself.

I will say, not dealing with a package.json and just having things auto-import and work… pretty darn cool!

Fetching our Birthdays

First things first, I fetch my .ical file and convert it into a list of events, taking advantage of Pipedream’s Environment Variables to securely store the link provided from our HR platform.

const bdayIcal = await rp(process.env.ICAL_FILE_URL);
const events = ical.sync.parseICS(bdayIcal);

We’ll be using this shortly.

What day is it again?

I need to figure out what day today is. To not unnecessarily bloat my code with NPM packages like moment.js (also recently deprecated…), I stuck with vanilla JS. A bit ugly, but does the trick.

const today = new Date();
today.setHours(0,0,0,0);
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const nextDay = new Date(today);
nextDay.setDate(today.getDate() + 2);

// What day of the week is it? 0 = Sunday, 6 = Saturday
const dayNum = today.getDay();
if (dayNum === 0 || dayNum === 6) {
    return; // don't run on weekends, could also be set with the cron schedule...
}

Add some spice

My opinion is that bots that look like bots are boring. I feel like our Slack Emoji game is pretty on point at Scale AI, and I wanted to take advantage of some of our favorites to bring my bot to life.

I enumerate a list of potential emojis to celebrate birthdays, as well as a list of messages that can be chosen if there are no birthdays that day.

// Birthday Message Base
let birthdayMsg = ""

// Birthday Emoji List
let birthdayEmojis = [
    'cake',
    'tada',
    'sparkling',
    'fast_parrot',
    'fiesta_parrot',
    'partying_face',
    'amaze',
    'cool_doge',
    'floss_avocado',
    'highfive',
    'mushroom_dance',
    'party_pikachu',
    'yay-avocado',
    'catjam'
]

let noBirthdayMsgs = [
    "No birthdays today :flushed: let's go hire some more Scaliens!",
    "No one was born today :sad-panda: Assuming 300 Scaliens, that's a 43.9% likely outcome. :nerd_face:",
    "Nothing to celebrate today :sad_parrot: Our parents must have had better things to do 39 weeks and some years ago :woman-shrugging: :man-shrugging:",
    "Not a single Scalien was born on this day :wow:",
    "If you have a clever remark about no one having a birthday today, this is the time to share it. :think-up: (No, seriously, we'll add it to the list)"
];

Whose birthday is today

Now that we have a list of birthdays and ways to celebrate them, we need to figure out whose birthday is today. I also didn’t want people whose birthday fell on the weekend to miss out, so I added some logic that would see if it’s Friday and if it was, it would include any birthdays on Saturday or Sunday.

for (const event of Object.values(events)) {
    const name = event.summary.replace(' - Birthday', ''); // Name of person

    isBirthday = false;
    
    if (dayNum > 0 && dayNum < 5) { // Monday - Thursday
        isBirthday = today.toISOString() == event.start.toISOString();
    } else { // It's Friday, because Sat / Sun are skipped above
        isBirthday = (
            today.toISOString() === event.start.toISOString() ||
            tomorrow.toISOString() === event.start.toISOString() ||
            nextDay.toISOString() === event.start.toISOString()
        )
    }

    if (isBirthday) {
        const month = event.start.toLocaleString('default', { month: 'long' }); // April
        const day = event.start.getDate(); // 25
        const emojiNum = Math.floor(Math.random() * birthdayEmojis.length);
        birthdayMsg = birthdayMsg + `> *${name}* - ${month} ${day} :${birthdayEmojis[emojiNum]}:\n> \n`
    }
};

When no one was born on this day

A bland “0 birthdays today” message didn’t seem fantastic.

Instead, if no birthdays were added to our birthdayMsg string, I come up with a back up plan where I choose a message from one of the options above.

As opposed to randomly choosing a message, though, I chose to make it based on the day of the month we were in so there could never be the same message two days in a row.

if (birthdayMsg) {
    birthdayMsg = ':birthday: *A very happy birthday to the following Scaliens* :birthday:\n\n' + birthdayMsg
} else {
    birthdayMsg = noBirthdayMsgs[today.getDate() % noBirthdayMsgs.length];
}
console.log(birthdayMsg);

Time to Celebrate!

At this point, our birthdayMsg is ready for the world.

I chose to use a Slack Webhook to paste my message into a #birthdays channel I made just for this. Slack Webhooks are great because you don’t need to mess with any API authentication or other things that get in the way. You simply make a POST request to the URL Slack provides and your message is posted.

await rp({
    method: 'POST',
    uri: process.env.BIRTHDAY_BOT_WEBHOOK_URL,
    body: {
        text: birthdayMsg
    },
    json: true // Automatically stringifies the body to JSON
});

Wrapping Up

BirthdayBot has already been a huge hit at Scale AI. People are stoked.

This took about 2 hours on the weekend to set up and I’d consider it time extremely well spent.

The code in it’s entirety is here: BirthdayBot - Pipedream

Honestly, I’m really bullish on the Pipedream experience. I love APIs and Integrations and this is exactly what I’ve always wanted from a developer experience.

Thanks Pipedream Team!

4 Likes

patiently waiting for my :cake: day

Love the detailed breakdown @shauntvanweelden ! Thanks for sharing.