Build a Scheduler Slackbot in 30 Minutes!
Tags: api, engineering, tips, productivity
Published: 2018-08-17 00:22:57

---
cover_image: https://thepracticaldev.s3.amazonaws.com/i/hymwf5d6gwzzn4kk9hcd.png
title: Build a Scheduler Slackbot in 30 Minutes!
published: True
tags: api, engineering, tips, productivity 
canonical_url: https://www.nylas.com/blog/build-a-slack-bot-scheduler-in-30-minutes
---

<p>The days of leaving Slack to create an event on your calendar are over!&nbsp;</p>
<!--more-->
<p style="text-align: left;">In this tutorial, you are going to learn how to create a scheduler bot that adds events to your personal calendar with a simple Slack slash command using the Nylas Calendar API.&nbsp;</p>
<h3><img src="https://cdn2.hubspot.net/hubfs/3314308/Slack%20Bot2%20(1).png" alt="Slack Bot2 (1)" width="515" style="width: 515px; display: block; margin-left: auto; margin-right: auto;"></h3>
<h2 style="text-align: left;"><strong>What You’ll Need Beforehand</strong></h2>
<p>There are a few systems that you’ll need to have in place before embarking on this DIY Slack bot journey!</p>
<ul>
<li><span style="font-size: 16px;"><a href="https://help.github.com/articles/set-up-git/" target="_blank">Git</a> &amp; <a href="https://github.com/" target="_blank">Github</a> account</span></li>
<li><span style="font-size: 16px;"><a href="https://signup.heroku.com/" target="_blank">Heroku</a>&nbsp;account</span></li>
<li><span style="font-size: 16px;"><a href="https://slack.com/" target="_blank">Slack</a> workspace</span></li>
<li><span style="font-size: 16px;"><span class="thread-630228555663276098190666 attrcomment attrcommentfirst thread-630228555663276098190666-first author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z h-ldquo">An</span><span class="thread-630228555663276098190666 attrcomment author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z"> email address associated with a Google or Microsoft</span><span class="thread-630228555663276098190666 attrcomment author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z s-lparen"> </span><span class="thread-630228555663276098190666 attrcomment author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z h-lparen">(Office</span><span class="thread-630228555663276098190666 attrcomment author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qovvuiz69z8jhz84zz82zxz77z3z69zz80zpvz74zz86ze4z88z9z77zaqe7z71zv9d h-lparen">3</span><span class="thread-630228555663276098190666 attrcomment author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z h-lparen">65</span><span class="thread-630228555663276098190666 attrcomment author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z"> or Outlook) calendar</span></span></li>
<li><span style="font-size: 16px;">A text editor of your choosing — PyCharm, Atom, Vim, Sublime, etc.</span></li>
</ul>
<h2 style="text-align: left;"><strong>Overview</strong></h2>
<p>Here are the high-level steps involved in building the scheduling bot:</p>
<p><span style="font-size: 16px;"><a href="#part-0" style="font-size: 14px; background-color: transparent;">Part 0: Basic app setup</a> <span style="background-color: transparent;"><br/>TLDR; Fork the starter code, run the setup script and run the app locally</span></span></p>
<p><span style="font-size: 16px;"><a href="#part-1" style="font-size: 14px; background-color: transparent;">Part 1: Hook your repo up to Heroku &amp; deploy it</a> <span style="background-color: transparent;"><br/>TLDR; Create a Heroku app, hook it up to your Github repo, deploy it</span></span></p>
<p><span style="font-size: 16px;"><a href="#part-2" style="font-size: 14px; background-color: transparent;">Part 2: Set up Heroku config variables</a><br/>TLDR; Auth an account with Nylas to get the access token, use this to get the ID of the calendar, add these plus the calendar timezone as config variables in Heroku.</span></span></p>
<p><span style="font-size: 16px;"><a href="#part-3" style="font-size: 14px; background-color: transparent;">Part 3: Connect your app to your Slack workspace</a><span style="background-color: transparent;"><br/>TLDR; Create a Slack App and configure a slash command to communicate with your app, add a route in your app that listens for the slash command&nbsp;</span></span></p>
<p><span style="font-size: 16px;"><a href="#part-4" style="font-size: 14px; background-color: transparent;">Part 4: Add text parsing functionality</a>&nbsp; &nbsp; <span style="background-color: transparent;"><br/>TLDR; Parse the text sent from Slack into meaningful components for an event</span></span></p>
<p><span style="font-size: 16px;"><a href="#part-5">Part 5: Build scheduling functionality</a>&nbsp; <span style="background-color: transparent;"><br/>TLDR; Send the parsed arguments to the /events endpoint of the Nylas API to create an event on your calendar.</span></span></p>
<h3>Ready? Let’s dive in!</h3>
<h2 id="part-0" style="text-align: left;"><strong>Part 0: Basic app setup</strong></h2>
<p><strong>Step 0: Fork the Slackbot starter code</strong></p>
<p>The code for this project lives in a repository on the Nylas Github account at <a href="https://github.com/nylas/slackbot" target="_blank">https://github.com/nylas/slackbot</a>.&nbsp;</p>
<p>You are going to fork and then clone this repository instead of just cloning it so that you have your own repository that you can connect to Heroku. Follow <a href="https://help.github.com/articles/fork-a-repo/" target="_blank">these steps</a> from Github to fork the repository. Follow the steps up until “Find another repository to fork”.</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531330588485_image.png" alt="null"></div>
<p>After, you will have a local copy of a directory called <code class="listtype-code listindent1 list-code1 lang-python">slackbot</code> . This directory has five files:</p>
<ol>
<li><span style="font-size: 16px;">Procfile - tells heroku how to run the app</span></li>
<li><span style="font-size: 16px;">app.py - the main app file with initial Flask app setup, you will do all of your development in this file</span></li>
<li><span style="font-size: 16px;">requirements.txt - the list of dependencies you need to install</span></li>
<li><span style="font-size: 16px;">runtime.txt - tells Heroku that your app is written in Python3</span></li>
<li><span style="font-size: 16px;">setup.sh - a script to setup your development environment</span></li>
</ol>
<p>For the rest of the tutorial, you will be executing all of your commands in the <code class="listtype-code listindent1 list-code1 lang-python">/slackbot</code> directory</p>
<p>In addition to the master branch, which you will be on by default, this repo also contains five other branches corresponding to each part of the tutorial. You can stay on the master branch as you build your Slack bot, but if you get stuck at any step then you can see the difference between your code and the example application code by using <code class="listtype-code listindent1 list-code1">git diff &lt;part-#&gt;.</code>&nbsp;So if you get stuck during Part 4, <code class="listtype-code listindent1 list-code1">git diff part-4</code> will show the difference between your code and the example code after part 4.&nbsp;</p>
<p><strong>Step 1: Run the Script&nbsp;</strong></p>
<p>The setup script sets up your development environment and installs necessary dependencies. Run:</p>
<p><code class="listtype-code listindent1 list-code1 lang-python">source setup.sh</code></p>
<p>After this script completes it will print "Set up complete!" in your terminal</p>
<p>This script will have activated a virtual environment which you will use to keep the development of your project isolated. If your terminal prompt is now prepended with <code class="listtype-code listindent1 list-code1 lang-python">(.venv)</code> your virtual environment has successfully been activated!</p>
<p>If you are interested in learning more about virtual environments and python3 check out <a href="https://help.dreamhost.com/hc/en-us/articles/115000695551-Installing-and-using-virtualenv-with-Python-3" target="_blank">https://help.dreamhost.com/hc/en-us/articles/115000695551-Installing-and-using-virtualenv-with-Python-3</a></p>
<p><strong>Step 2: Run the app locally</strong></p>
<p><code class="listtype-code listindent1 list-code1">export FLASK_ENV=development</code></p>
<p><code class="listtype-code listindent1 list-code1">python3 app.py</code></p>
<p>You should see:</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531180157293_Screen+Shot+2018-07-09+at+4.46.21+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>If you visit the URL on the 4th line that the app is running on, you will see <code class="listtype-code listindent1 list-code1 lang-python">Howdy Hacker!</code></p>
<p>Wohoo! You made it through the app set up. Pat yourself on the back and crack open a La Croix.&nbsp;</p>
<h2 id="part-1" style="text-align: left;"><strong>Part 1: Hook your repo up to Heroku</strong></h2>
<p><strong>Step 0: Create a new Heroku app</strong></p>
<p>You could use DigitalOcean or DIY if you’d prefer but these instructions will be for Heroku.</p>
<p>Log in to heroku: <a href="https://id.heroku.com/login" target="_blank">https://id.heroku.com/login</a>,&nbsp;and create a new application by clicking <code>new</code> in the top right corner and completing the new app form</p>
<p><span style="background-color: transparent;">You can enter your own app name or leave it blank and let Heroku generate one for you! Make note of this url as you will need it in Part 3 when you connect your application to Slack.&nbsp;&nbsp;</span></p>
<p><strong>Step 1: Hook up your Github repo to Heroku<span>&nbsp;</span></strong></p>
<p>Heroku has an integration with Github which enables automatic deploys. This means that whenever you push code to a branch on Github, Heroku will deploy this code. How handy is that!</p>
<p><br>On the deploy page that you get redirected to after creating an application, in the <strong>Deployment method </strong>section, click <code class="listtype-code listindent1 list-code1 lang-python">Connect to GitHub</code> and then in the <strong>Connect to Github</strong> section, click the <code class="listtype-code listindent1 list-code1 lang-python">Connect to GitHub</code> button.</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531183138050_Screen+Shot+2018-07-09+at+5.25.56+PM.png" alt="null"><span style="color: #648785; font-size: 16px; background-color: transparent;">&nbsp;</span></div>
<p>Next, you will be taken to a page where you can select which repository to connect. If you have successfully created a repository under your github account, then it should come up when you start to type the repository name into the input.&nbsp;</p>
<p>Once you have connected up the repository, click <code class="listtype-code listindent1 list-code1 lang-python">Enable Automatic Deploys</code> for the master branch. This will simplify the deploy process so that any time you push to master, heroku will deploy the latest changes.&nbsp;</p>
<p>It’s important to note that if you start working on a branch other than master, then you will not have automatic deploys. You can manually deploy code from another branch if you push your code to the other branch select that branch from the manual deploy section and click <code class="listtype-code listindent1 list-code1 lang-python">Deploy Branch</code>.</p>
<p>&nbsp;</p>
<div><img src="https://cdn2.hubspot.net/hubfs/3314308/image_preview-1.png" alt="image_preview-1"></div>
<p>&nbsp;</p>
<p>Keep Heroku open because you will need it in Part 4 - Step 3.</p>
<p><strong>Step 2: Push code to master to trigger a deploy</strong></p>
<p>Quit your locally running app with <code class="listtype-code listindent1 list-code1 lang-python">CTRL+C</code>.&nbsp;<span class="thread-171340150517809745064260 attrcomment attrcommentfirst thread-171340150517809745064260-first author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z">Lets make a change to commit and add another exclamation point to your return statement.</span></p>
<p>The route should now look like</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python">@app.route('/')<br>
def homepage():<br>
   return "Howdy hacker!!"</code></pre>
<p>In your terminal, run:</p>
<p><code class="listtype-code listindent1 list-code1 lang-python">git add .</code></p>
<p><code class="listtype-code listindent1 list-code1 lang-python">git commit -m 'Part 1: Hook up repo to Heroku'</code></p>
<p><code class="listtype-code listindent1 list-code1 lang-python">git push origin master</code></p>
<p>After this deploy is complete — it may take a few seconds — visit the url of your app. You should be greeted with the message <code class="listtype-code listindent1 list-code1 lang-python">Howdy Hacker!!</code>. Your website is live and ready to welcome any hacker who visits the url, all thanks to the automatic deploy you configured.&nbsp;<span style="background-color: transparent;">&nbsp;</span></p>
<h2 style="text-align: left;"><strong>Part 2: Set up Heroku config variables</strong></h2>
<p>Okay, so to make this work you need 2 major things. First, you need an access token that indicates that you have authorized your account to be accessed through the Nylas API. This is an important step because the API cannot add an event to any old calendar unless it has been authenticated and the owner has given permission. Second, you need the ID of the calendar you want to add events to. Most accounts have a few calendars — some autogenerated and some created by the user. Without this, the API would not know which calendar to send the request for.</p>
<p>Next, you’ll set these as config variables in Heroku so that you’ll avoid adding and committing them to code in your app.&nbsp;</p>
<p>In Step 0, you will get an access token and in Step 1, you will use this access token to find the ID for the calendar that you wish to add events to. Then, in Step 3 you will add these as config variables to your Heroku app.&nbsp;</p>
<p style="text-align: left;"><strong>Step 0: Get an access token</strong></p>
<p>Head over to <a href="https://dashboard.nylas.com/register" target="_blank">https://dashboard.nylas.com/register</a> to register for a free Nylas account or to <a href="https://dashboard.nylas.com/sign-in" target="_blank">https://dashboard.nylas.com/sign-in</a> to sign in to an existing account. Once you’ve signed into the Nylas dashboard, click Accounts in the left side bar.</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531260178164_Screen+Shot+2018-07-10+at+2.56.06+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>On the Accounts page, click <code class="listtype-code listindent1 list-code1 lang-python">Auth Account</code> in either the top right or if you have no previously authed accounts, in the center of the page.</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531260180284_Screen+Shot+2018-07-10+at+2.55.47+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>In the input window that pops up, type the email address associated with the calendar that you want to add events to and follow the authentication steps.&nbsp;</p>
<p>When you complete authentication, you will be redirected back to the Accounts page of the dashboard. At the top of the page will be a blue notification that looks like:</p>
<div><img src="https://cdn2.hubspot.net/hubfs/3314308/image_preview-2.png" alt="image_preview-2"></div>
<p>&nbsp;</p>
<p>From the blue notification, copy the value of the access token to a temporary place — you will need this token in the following two steps. In this example, the access token is <code class="listtype-code listindent1 list-code1 lang-python">xyz123xyz123xyz123xyz123xyz123.</code>&nbsp;</p>
<p>If you dismiss the notification or reload the page, the access token will disappear. For security reasons, there is no way to retrieve that specific token so if you lose your access token and need to get a new one, click <code class="listtype-code listindent1 list-code1 lang-python">Auth Account</code> and follow the authorization steps. You can re-auth a previously authenticated account no problem! This will create a new access token for the account.&nbsp;</p>
<p>You will use this token first in the Nylas docs to get the ID of the calendar and second when you add it to Heroku config variables.</p>
<p>You can keep the dashboard page open and as long as you don’t navigate away or reload it, the blue notification with the access token will stay at the top of the page.</p>
<p style="text-align: left;"><strong>Step 1: Get the calendar ID</strong></p>
<p>You can’t create an event without telling it what calendar it needs to be added to so you need to get the ID of the calendar you want to add events to.</p>
<p>Head over to <a href="https://docs.nylas.com/reference#calendars-1" target="_blank">https://docs.nylas.com/reference#calendars-1</a>. This is the calendar section of the Nylas docs and specifically the <code class="listtype-code listindent1 list-code1 lang-python">GET /calendars endpoint</code>. You could hit the Nylas API by making a request to <code class="listtype-code listindent1 list-code1 lang-python">https://api.nylas.com/calendars</code> in your terminal, but the docs are interactive and make it possible to do in two steps within the site.&nbsp;</p>
<p>Paste your access token into the <code class="listtype-code listindent1 list-code1 lang-python">Authorization</code> input field at the bottom of the inputs for this endpoint section.&nbsp;</p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531262232159_Screen+Shot+2018-07-10+at+3.32.36+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>If you then scroll back up to the code in the dark box above, the <code class="listtype-code listindent1 list-code1 lang-python">authorization:</code>&nbsp; will have been automatically filled out.</p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531262370948_Screen+Shot+2018-07-10+at+3.35.36+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>Next, click <code class="listtype-code listindent1 list-code1 lang-python">Try It</code> in the top right corner. This will run the <code class="listtype-code listindent1 list-code1 lang-python">cURL</code> request on the left and hit the Nylas API with your access token and display the response on the right. This will be a list of your calendars.&nbsp;</p>
<p>From the JSON list of calendars, select which calendar you want to add events to. Some of the calendars you may have never seen before. That is because some providers have default calendars that they automatically generate. One common example is “Holidays”. Often, these automatic calendars will have <code class="listtype-code listindent1 list-code1 lang-python">"read_only": True</code>. This means that you don’t have permissions to create events on those calendars. It is important to select a calendar that has <code class="listtype-code listindent1 list-code1 lang-python">"read_only": False.</code> Copy the <code class="listtype-code listindent1 list-code1 lang-python">id</code> from your selected calendar.&nbsp;</p>
<p>In the example screenshot above, the <code class="listtype-code listindent1 list-code1 lang-python">id</code> of the top calendar is <code class="listtype-code listindent1 list-code1 lang-python">"67qmz3fuk9wfljwj1w8ngshkc".</code>&nbsp;You will have a different value after you run Try It because the ID will be a unique identifier to your calendar.&nbsp;&nbsp;</p>
<p><strong style="background-color: transparent;">Step 2: Add config variables to Heroku</strong></p>
<p>Go to Heroku and navigate to the settings page for your app. Click <code class="listtype-code listindent1 list-code1 lang-python">Reveal Config Vars</code>. This will pop open a pair of inputs where the key, or how you want to refer to the variable in your code, is on the left and the value is on the right.&nbsp;</p>
<p>Add your calendar ID as a config variable with a key of <code class="listtype-code listindent1 list-code1 lang-python">CALENDAR_ID</code> and a value of the ID that you copied in Step 1. Make sure to remove the double quotes from the ID.&nbsp;</p>
<p>Next, you are going to add the access token from Step 0 as a config variable with a key of <code class="listtype-code listindent1 list-code1 lang-python">ACCESS_TOKEN</code> and the value from Step 0.&nbsp;</p>
<p>Finally, you need to add a config variable with your calendar timezone so that your calendar can properly schedule events. If you don’t pass the timezone, then your calendar will assume UTC (Universal Time Coordinated) also known as GMT (Greenwich Mean Time). If your calendar is in any other timezone, then the evens will show up shifted by the timezone UTC offset. Setting the timezone config variable will avoid this!&nbsp;</p>
<p>Since I am writing this in California and it is currently daylight savings, the value will be <code class="listtype-code listindent1 list-code1 lang-python">PDT</code>. You can also set the value to the UTC offset, which for me would be <code class="listtype-code listindent1 list-code1 lang-python">-0700</code>. You can find your timezone information <a href="https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations" target="_blank">here</a>. If you want to use the UTC offset then it needs to be in the proper format. A timezone of UTC+10 would be <code class="listtype-code listindent1 list-code1 lang-python">+1000</code> and a timezone of UTC-3 would be <code class="listtype-code listindent1 list-code1 lang-python">-0300</code>.</p>
<p>Here is how it looked for me:</p>
<p>&nbsp;</p>
<div><img src="https://cdn2.hubspot.net/hubfs/3314308/image_preview-3.png" alt="image_preview-3"></div>
<p>&nbsp;</p>
<p>Or with UTC offset:</p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531264746932_Screen+Shot+2018-07-10+at+4.12.02+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>Sweet now that everything in Heroku is configured, we can dive into the exciting next steps.&nbsp;</p>
<h2 id="part-3" style="text-align: left;"><strong>Part 3: Connect your app to Slack</strong></h2>
<p><strong>Step 1: Create a Slack app</strong></p>
<p>Go to <a href="https://api.slack.com/apps?new_app=1" target="_blank">https://api.slack.com/apps?new_app=1</a>. This is the landing page for building a new Slack app.</p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_23A4CD528EBB9FE5912B9C3F2BF4F0B1B5BDBBA2881E8512A634DDE0D3EF3B57_1530226678465_Screen+Shot+2018-06-28+at+3.56.58+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>If the pop up above does not appear, click <code class="listtype-code listindent1 list-code1 lang-python">Create New App</code>.</p>
<p>Fill in the <code class="listtype-code listindent1 list-code1 lang-python">App Name</code> with “Scheduler” or whatever you would like to name this app. The name you select here is not too important.</p>
<p>Next select the development workspace in which you want to use this app. If you are not signed into your Slack account, when you click the <code class="listtype-code listindent1 list-code1 lang-python">Development Slack Workspace</code> drop down the only option that will appear is <code class="listtype-code listindent1 list-code1 lang-python">Sign in to another workspace</code>. Select this and follow these instructions. This will get you to sign into your workspace on desktop. Once this is successful, head back to <a href="https://api.slack.com/apps?new_app=1" target="_blank">https://api.slack.com/apps?new_app=1</a> and fill out the pop up again. This time, there should be workspace options in the dropdown. Select which workspace you want to add this scheduler app to and hit <code class="listtype-code listindent1 list-code1 lang-python">Create App</code>.</p>
<p style="text-align: left;"><strong>Step 2: Configure Slack app</strong></p>
<p>You will be taken to an app dashboard. Here, there are lots of options for what type of application and functionality you want to build. You will be making a slash command so select the <code class="listtype-code listindent1 list-code1">Slash Commands</code> option.&nbsp;</p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_23A4CD528EBB9FE5912B9C3F2BF4F0B1B5BDBBA2881E8512A634DDE0D3EF3B57_1530227635007_Screen+Shot+2018-06-28+at+4.06.17+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>Then select <code class="listtype-code listindent1 list-code1 lang-python">Create New Command</code>. This will take you to a slash command configuration form.&nbsp;</p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531184636689_Screen+Shot+2018-07-09+at+5.58.05+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p><strong>Command</strong></p>
<p>You can name the command however you want to invoke it when you use it. I choose <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code> because I think it looks cute when invoked in full:&nbsp;</p>
<p><code class="listtype-code listindent1 list-code1 lang-python">/scheduleme "Dinner with James" "Tomorrow at 7pm" "Tomorrow at 9pm"</code></p>
<p>but you can select whatever slash command tickles your fancies.&nbsp;</p>
<p><strong>Request URL</strong></p>
<p>For the <code class="listtype-code listindent1 list-code1 lang-python">Request URL</code> input, copy the url that your heroku app was deployed to on step 1 and paste it in the input. Then at the end of the url, add a <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code> so the url will look something like <code class="listtype-code listindent1 list-code1 lang-python">https://my-scheduler-bot.herokuapp.com/scheduleme</code>.</p>
<p>This is setting up where Slack should send the request from the slash command. In otherwords, when you invoke a slash command, Slack needs to know where to send the data. This is specifying a url and a specific route on that url, <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code>. &nbsp;You will define this route in your python file in Part 5!&nbsp;</p>
<p><strong>Short description</strong></p>
<p>Add a short description to help you remember what this command does. This will pop up in Slack when you are typing commands that match.&nbsp;</p>
<p>For mine, I put <code class="listtype-code listindent1 list-code1 lang-python">Adds an event to my calendar!</code></p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531185146535_Screen+Shot+2018-07-09+at+6.12.13+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p><strong>Usage Hint</strong></p>
<p>This is a hint for how to properly invoke the slash command. As you can see in the screen shot above, this will also pop up when you start typing the command.&nbsp;</p>
<p>For mine, I put <code class="listtype-code listindent1 list-code1 lang-python">“title” “start date &amp; time” “end date &amp; time”</code>.</p>
<p>The scheduler will be expecting three arguments, each in double quotes. &nbsp;The first argument should be the title of the event, the second should be the start date and time and the third should be the end date and time. You will see how these get parsed in when you build out the text parsing functionality in Part 4.</p>
<p>Click <code class="listtype-code listindent1 list-code1 lang-python">Save</code> in the bottom right corner and you will be redirect back to your app homepage.&nbsp;</p>
<p><strong>Step 3: Install the app in your workspace</strong></p>
<p>On the sidebar, click <code class="listtype-code listindent1 list-code1 lang-python">Install App</code></p>
<p>&nbsp;</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531859978889_image.png" alt="null"></div>
<p>&nbsp;</p>
<p>Follow the steps to install the app in your workspace. Without this step, your workspace won’t know about your app and its slash command.&nbsp;</p>
<p><strong>Step 4: Add the /scheduleme route to your application</strong></p>
<p>In the previous step, you connected your Slack slash command up to the url of your heroku app + <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code>. But what is <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code> referring to? Nothing at the moment!</p>
<p>Let’s fix that. In your file <code class="listtype-code listindent1 list-code1 lang-python">app.py</code> lets add another route. You can add a route with the url <code class="listtype-code listindent1 list-code1 lang-python">scheduleme</code> to match what you appended to the end of your heroku app url in the <code class="listtype-code listindent1 list-code1 lang-python">Create New Command</code> form on Slack. You will be doing data processing in this route with the information from the slash command. To indicate that data is sent with the request, you need to add <code class="listtype-code listindent1 list-code1 lang-python">methods=['POST']</code> as the second <code class="listtype-code listindent1 list-code1 lang-python">@app.route</code> parameter. The function name on line 14 doesn’t matter in this case, but for the sake of consistency, you can call it <code class="listtype-code listindent1 list-code1 lang-python">scheduleme</code> as well.&nbsp;</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python">from flask import Flask
app = Flask(__name__)
PORT = 4390

@app.route('/')
def homepage():
	return "Howdy hacker!!"

@app.route('/scheduleme', methods=['POST'])
def scheduleme():
	return 'I would like to schedule that, but I haven\'t quite figured out how...'

if __name__ == '__main__':
	app.run(debug=True, port=PORT)
</code></pre>
<p>This function doesn’t do much — it just returns some text. But lets deploy it to make sure you properly connected your app up to Slack.&nbsp;</p>
<p>Add, commit and push this code to master to make it live!</p>
<p>Then, go to your Slack workspace and type in <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code> and hit enter. Your bot should respond with:</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531256268768_Screen+Shot+2018-07-10+at+1.57.06+PM.png" alt="null"></div>
<p>&nbsp;</p>
<p>You have officially made a Slack bot! Now lets add some functionality!</p>
<p name="debugging"><strong>Debugging</strong></p>
<p>If your bot responded properly, skip this section and continue onto Part 4!</p>
<p>If you get a <code class="listtype-code listindent1 list-code1 lang-python">404</code> here, there are a few strategies to identify whats going wrong.</p>
<p>To see if the issue is with your application code, user a cURL request to hit that endpoint.</p>
<p><code class="listtype-code listindent1 list-code1 lang-python">curl -X POST -F 'text="Post tutorial celebration dance" "Now" "Today at 11pm"' https://&lt;your-app-url&gt;/scheduleme</code></p>
<p>Replace <code class="listtype-code listindent1 list-code1 lang-python">&lt;your-app-url&gt;</code><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z95k2z71zvz76z8vo03rz75zoz88zz81zz72zz83zz71znz75z5z72zawjz71z1wz84z">with your Heroku app url. This command is bypassing Slack, and hitting your application code directly. If the bot does not respond properly, then the problem must be with your application. If your bot does respond properly, then the issue is likely from the connection with your Slack slash command.&nbsp; </span></p>
<p><strong>Application Problems</strong></p>
<ul>
<li><span style="font-size: 16px;">Does your code matches the code above?</span></li>
<li><span style="font-size: 16px;">Has this new code been deployed — either automatically if you have that set up or otherwise manually via the Heroku UI or Heroku command line interface?</span></li>
<li><span style="font-size: 16px;">Run the app locally and cURL it from the command line</span></li>
</ul>
<p><code class="listtype-code listindent1 list-code1 lang-python">curl -X POST -F 'text="Post tutorial celebration dance" "Now" "Today at 11pm"' https://127.0.0.1:4390/scheduleme</code></p>
<ul>
<li>If you have the Heroku command line interface installed, you can see the logs with&nbsp;</li>
</ul>
<p><code class="listtype-code listindent1 list-code1 lang-python">heroku logs --tail -a &lt;your-app-name&gt;</code>;</p>
<ul>
<ul>
<li>You have to be logged in via heroku login for this to work.&nbsp;</li>
</ul>
</ul>
<p><strong>Connection Problems</strong></p>
<ul>
<li>In Slack, when you type in <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code> does the command help pop up? If not, your app likely has not be installed to your workspace. Make sure Step 3 was completed properly.&nbsp;</li>
<li>On the edit command page that you filled out in Step 2, does your request url end in <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code></li>
</ul>
<h2 id="part-4" style="text-align: left;"><strong>Part 4: Add text parsing functionality</strong></h2>
<p>When you use the slash command, you are going to send some text with it. In this step, you’re going to parse that text and make sure you have the correct number of arguments.</p>
<p><strong>Step 0: Add new dependencies</strong></p>
<p>For parsing the request sent by Slack, you are going to use two new dependencies. First, you are going to import <code class="listtype-code listindent1 list-code1 lang-python">request</code> from Flask. You will use this to access the information in the request. Next you are going to unpack the text of the request using a regular expression. For this you need to add &nbsp;<code class="listtype-code listindent1 list-code1 lang-python">import re</code> to your import section.</p>
<p>The top of the file will now look like:</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">from flask import Flask, request
import re
</code></pre>
<p><strong>Step 1: Get the text from the request</strong></p>
<p>Using the <code class="listtype-code listindent1 list-code1 lang-python">request</code> library, you will need to get the text sent with the slash command. You can do this by adding <code class="listtype-code listindent1 list-code1 lang-python">raw_text = request.form.get('text')</code> at the top of your <code class="listtype-code listindent1 list-code1 lang-python">scheduleme</code> route.&nbsp;</p>
<p><strong>Step 2: Unwrap the text</strong></p>
<p>The text that is sent from the slash command is the string following the command name. For example, if you type <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme "Workout" "Tomorrow at 7:30am" "Tomorrow at 8:30am"</code> into Slack, the text that you will get in the previous step will <code class="listtype-code listindent1 list-code1 lang-python">"Workout" "Tomorrow at 7:30am" "Tomorrow at 8:30am"</code>. It is important to note that this text is wrapped in single quotes with each of the three components wrapped in double quotes. You can use a regular expression to unwrap the text from single quotes and put all the components into an array.</p>
<p><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">text_array = re.findall(r'"(.*?)"', raw_text)</code></p>
<p><strong>Step 3: Error handling</strong></p>
<p>You should make sure that you have the proper number of arguments and warn if not.</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">if len(text_array) != 3: 
    return 'The format is /scheduleme "[title]" "[start date &amp; time]" "[end date &amp; time]"'</code></pre>
<p><strong>Step 4: Pull out event components</strong></p>
<p>Finally, lets pull out the different components from the array and give them better names.&nbsp;</p>
<p><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">title, start, end = text_array</code></p>
<p>Then to make sure this is all working swimmingly, you can pass them all to a return statement like:</p>
<p><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">return 'Sweet I parsed the title: {}, start: {} and end: {}'.format(title, start, end)</code></p>
<p>At the end of this section, your app.py file will look like:</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python">from flask import Flask, request
import re
import os
import dateparser
import requests
 
app = Flask(__name__)
 
PORT = 4390
 
@app.route('/')
def homepage():
    return "Howdy hacker!!"
 
@app.route('/scheduleme', methods=['POST'])
def scheduleme():
    raw_text = request.form.get('text')

	text_array = re.findall(r'["“”‘’\'](.*?)["“”‘’\']', raw_text)
	if len(text_array) != 3:
		return 'The format is /scheduleme "[title]" "[start date &amp; time]" "[end date &amp; time]"'
	title, start, end = text_array
	
    return f'Sweet I parsed the title: {title}, start: {start} and end: {end}'
    
if __name__ == '__main__': 
	app.run(debug=True, port=PORT)</code></pre>
<p>Add, commit and push this code! To test it, type in a full <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme</code> command to Slack like:</p>
<div><img src="https://cdn2.hubspot.net/hubfs/3314308/image_preview-5.png" alt="image_preview-5"></div>
<p>and you should see:</p>
<div><img src="https://d2mxuefqeaa7sj.cloudfront.net/s_9E966E4D153A92A6C1EE7A51F0576B6B726D6CE9A933DDB5AB33E608A1C0317A_1531258937486_Screen+Shot+2018-07-10+at+2.41.35+PM.png" alt="null"></div>
<h2 id="part-5" style="text-align: left;"><strong>Part 5: Build scheduling functionality</strong></h2>
<p>This is your last part — hooray you are almost finished! In this last step, you’re going to sent the request to the Nylas API that will create an event on your calendar.&nbsp;</p>
<p><strong>Step 0: Access the config variables in your code</strong></p>
<p>To access config variables in your code, you will need to add another dependency, <code class="listtype-code listindent1 list-code1 lang-python">os</code>. Add the line <code class="listtype-code listindent1 list-code1 lang-python">import os</code> to the bottom of your import statements.&nbsp;</p>
<p>Next, lets use <code class="listtype-code listindent1 list-code1 lang-python">os</code> to pull the values of your config variables from Heroku into your code. Replace the return statement with:</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">calendar_id = os.environ.get('CALENDAR_ID')
assert calendar_id is not None, 'Missing `CALENDAR_ID` config variable'
access_token = os.environ.get('ACCESS_TOKEN')
assert access_token is not None, 'Missing `ACCESS_TOKEN` config variable'
timezone = os.environ.get('TIMEZONE')
assert timezone is not None, 'Missing `TIMEZONE` config variable'</code></pre>
<p><strong style="background-color: transparent;">Step 1: Build request components</strong></p>
<p>You are going to use the <code class="listtype-code listindent1 list-code1 lang-python">requests</code> library to send the request to the Nylas API. Add <code class="listtype-code listindent1 list-code1 lang-python">import requests</code> to your import statements. You are also going to use <code class="listtype-code listindent1 list-code1 lang-python">dateparser</code> which takes a variety of inputs for example, “Today at 3pm”, “12/31/2018 at 11:30pm”, “Friday at 9am” and turns them into datetime objects. Using this library gives you more flexibility for what you can type in as the start and end components of the slash command. Add <code class="listtype-code listindent1 list-code1 lang-python">import dateparser</code> to your import statements.&nbsp;</p>
<p>The request is comprised of a few components — a URL, headers and json. First, you will create a dictionary of the <code class="listtype-code listindent1 list-code1 lang-python">timezone_settings</code>. You will pass this into <code class="listtype-code listindent1 list-code1 lang-python">dateparser.parse()</code> to indicate that you want the date to be parsed into a timezone aware datetime object.&nbsp;</p>
<p><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">timezone_settings = {'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True}</code></p>
<p><span style="background-color: transparent;">Now you have all the information to create the meat of the request, the <code class="listtype-code listindent1 list-code1 lang-python">json</code> argument. For this, you will create a dictionary with <code class="listtype-code listindent1 list-code1 lang-python">calendar_id</code>, <code class="listtype-code listindent1 list-code1 lang-python">title</code> and <code class="listtype-code listindent1 list-code1 lang-python">when</code> keys. The when dictionary has two keys <code class="listtype-code listindent1 list-code1 lang-python">start_time</code> and <code class="listtype-code listindent1 list-code1 lang-python">end_time</code>.</span><span style="background-color: transparent;">&nbsp;</span></p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">json = {
		'calendar_id': calendar_id, 
		'title': title, 
		'when': {
				'start_time': int(dateparser.parse(start, settings=timezone_settings).timestamp()), 
				'end_time': int(dateparser.parse(end, settings=timezone_settings).timestamp())
			}
		}</code></pre>
<p><span style="background-color: transparent;">There’s a lot going on in the values of <code class="listtype-code listindent1 list-code1 lang-python">start_time</code> and <code class="listtype-code listindent1 list-code1 lang-python">end_time</code>! The first step, <code class="listtype-code listindent1 list-code1 lang-python">dateparser.parse(start, settings=timezone_settings)</code>, is parsing the string text into a timezone aware datetime. Then, <code class="listtype-code listindent1 list-code1 lang-python">.timestamp()</code> is turning it into a </span><a href="https://en.wikipedia.org/wiki/Unix_time" target="_blank" style="background-color: transparent;">unix timestamp</a><span style="background-color: transparent;">. This timestamp is a float so the final step is turning it into an integer with <code class="listtype-code listindent1 list-code1 lang-python">int()</code>.</span></p>
<p>The final building block for the request is the headers where you will pass in the access token to prove that you have authorized your account.&nbsp;</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">headers = {'authorization': access_token}</code>&nbsp;</pre>
<p>Finally, bring all these pieces together and wrap it in a a try except block to capture any exceptions.</p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">try: 
    response = requests.post('https://api.nylas.com/events', headers=headers, json=json) 
    if response.status_code == 200: 
        return f'Wohoo! {title} was scheduled from {start} to {end}' 
    else: 
        return f'Error! Our response has a status of {response.status_code} and text {response.text}' 
except Exception as e: 
    return f'An exception {e} occurred creating the event!'</code></pre>
<p>Use the requests library to make a post request to the URL <code class="listtype-code listindent1 list-code1 lang-python">'https://api.nylas.com/events'</code> passing in the headers and the json as key word arguments.&nbsp;</p>
<p>Your app.py file will end up like<span style="background-color: transparent;">&nbsp;</span></p>
<pre><code class="listtype-code listindent1 list-code1 lang-python" spellcheck="false">from flask import Flask, request
import re
import os
import dateparser
import requests

app = Flask(__name__)
PORT = 4390
@app.route('/')

def homepage():
	return "Howdy hacker!!"

@app.route('/scheduleme', methods=['POST'])
def scheduleme():
	raw_text = request.form.get('text')
	
	text_array = re.findall(r'["“”‘’\'](.*?)["“”‘’\']', raw_text)
	if len(text_array) != 3:
		return 'The format is /scheduleme "[title]" "[start date &amp; time]" "[end date &amp; time]"'
	title, start, end = text_array
	
	calendar_id = os.environ.get('CALENDAR_ID')
	assert calendar_id is not None, 'Missing `CALENDAR_ID` config variable'
	access_token = os.environ.get('ACCESS_TOKEN')
	assert access_token is not None, 'Missing `ACCESS_TOKEN` config variable'
	timezone = os.environ.get('TIMEZONE')
	assert timezone is not None, 'Missing `TIMEZONE` config variable'

    timezone_settings = {'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True
    json = {
		'calendar_id': calendar_id, 
		'title': title, 
		'when': {
				'start_time': int(dateparser.parse(start, settings=timezone_settings).timestamp()), 
				'end_time': int(dateparser.parse(end, settings=timezone_settings).timestamp())
			}
		}
    headers = {'authorization': access_token}

    try:
	    if response.status_code == 200:
		    return f'Wohoo! {title} was scheduled from {start} to {end}'
	    else:
		    return f'Error! Our response has a status of {response.status_code} and text {response.text}'
    except Exception as e:
	    return f'An exception {e} occurred creating the event!'

if __name__ == '__main__':
	app.run(debug=True, port=PORT)</code></pre>
<p>Add, commit and push this. Yay, your Slackbot is complete! Head over to Slack and enter <code class="listtype-code listindent1 list-code1 lang-python">/scheduleme "Post tutorial celebration dance" "Now" "Today at 11pm".</code> Then, head over to your calendar and you will see a well deserved celebration dance for scheduled, appropriately, for the rest of the day.&nbsp;</p>
<p>If you run into any issues along the way, checkout the <a href="#debugging">debugging section</a> for help!&nbsp;</p>
<h2>Next steps for those who are so inclined…&nbsp;</h2>
<p>This is a basic scheduler Slack bot — it just adds an event with a title. The Nylas API lets you create events with a lot more information associated with them. Some cool extensions would be to add the functionality to support:</p>
<ul>
<li><span style="font-size: 16px;">Creating events with descriptions</span></li>
<li><span style="font-size: 16px;">Creating events with locations&nbsp;</span></li>
<li><span style="font-size: 16px;">Adding participants to events</span></li>
<li><span style="font-size: 16px;">Creating recurring events</span></li>
<li><span style="font-size: 16px;">Updating existing events</span></li>
<li><span style="font-size: 16px;">Deleting existing events</span></li>
<li><span style="font-size: 16px;">Adding events to different calendars</span></li>
</ul>
<br>
<p>&nbsp;</p>
<p>&nbsp;</p>