Skip to content

Commit

Permalink
finishing app
Browse files Browse the repository at this point in the history
  • Loading branch information
omar2535 committed Sep 8, 2020
1 parent a128744 commit 5a650ae
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 13 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/*
images/*
*.vscode
notes/*
notes/*
config/*
config
39 changes: 33 additions & 6 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
const fs = require('fs');
const yaml = require('js-yaml');
const puppeteer = require('puppeteer');
const step1Handler = require('./handlers/step1_handler');
const step2Handler = require('./handlers/step2_handler');
const queryCalendarTimes = require('./handlers/query_calendar_times_handler');
const queryCalendarDates = require('./handlers/query_calendar_available_dates_handler');
const generateDateRangeArray = require('./utils/DateHelpers');
const sendEmailNotification = require('./handlers/email_notification_handler');

let step1Option = 1;
let step2Option = 10;
let startDate = '2020-09-01';
let endDate = '2020-10-30';

// parse from config file first
let config = loadConfig();
let step1Option = config.Step1;
let step2Option = config.Step2;
let interval = config.Interval;
let shouldSendEmail = config.ShouldSendEmail == "true" ? true : false;
let startDate = config.StartDate;
let endDate = config.EndDate;

(async() => {
const browser = await puppeteer.launch({args: [
Expand Down Expand Up @@ -77,10 +83,31 @@ let endDate = '2020-10-30';
availabilityResults[`${date}`].push(dateAndTime.time);
});
}
console.log(`UTC TIME : ${new Date()}`);
console.log(availabilityResults);
console.log(`---------------------------------------------------------------------`);

if( (!(Object.keys(availabilityResults).length === 0
&& availabilityResults.constructor === Object))
&& shouldSendEmail) {
sendEmailNotification(availabilityResults);
}

await new Promise(r => setTimeout(r, 20000));
await new Promise(r => setTimeout(r, interval));
}

await browser.close();
})();

/**
* @returns {Object} javascript object of config/config.yml file
*/
function loadConfig() {
try {
let fileContents = fs.readFileSync('./config/config.yml', 'utf8');
let data = yaml.safeLoad(fileContents);
return data;
} catch (e) {
console.log(e);
}
}
11 changes: 6 additions & 5 deletions config/config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Parameters:
StartDate: 2020-09-01
EndDate: 2020-12-01
Step1: 3
Step2: 10
StartDate: "2020-09-01"
EndDate: "2020-10-30"
Step1: 1
Step2: 10
Interval: 300000
ShouldSendEmail: "false"
56 changes: 56 additions & 0 deletions handlers/email_notification_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const nodemailer = require('nodemailer');
const fs = require('fs');
const yaml = require('js-yaml')


function sendEmailNotification(result) {
let config = loadGmailConfig();
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: config.user,
pass: config.pass
}
});

var mailOptions = {
from: config.user,
to: config.receiver,
subject: config.subject,
html: generateEmailBody(result)
};

transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
}

function loadGmailConfig() {
try {
let fileContents = fs.readFileSync('./config/email_config.yml', 'utf8');
let data = yaml.safeLoad(fileContents);
return data;
} catch (e) {
console.log(e);
}
}

function generateEmailBody(result) {
let email_body = "";
email_body += "<h1>ICBC Watcher Notification</h1>"
for (const date in result) {
email_body += `<h3>${date}</h3>`
email_body += `<ul>`
result[`${date}`].forEach(time => {
email_body += `<li>${time}</li>`
})
email_body += `</ul>`
}
return email_body;
}

module.exports = sendEmailNotification;
Binary file added images/google-account-less-secure-prompt.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/step1.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"license": "ISC",
"dependencies": {
"chalk": "^4.1.0",
"js-yaml": "^3.14.0",
"nodemailer": "^6.4.11",
"puppeteer": "^5.2.1",
"request": "^2.88.2"
}
Expand Down
61 changes: 61 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# ICBC Web Booking Availability Checker

This is a small program to check ICBC's available times based on their Qmatic web form [here](https://onlinebusiness.icbc.com/qmaticwebbooking/#/). The purpose this was created was due to the frustratingly limited capacity that ICBC has for bookings per day to a point that people have to constantly refresh their form to check for available dates.

## Set up

Setup of this package is relatively simple.

### Gmail Account (optional)

This tool can be used with a gmail account to send email notifications. To do this, 2FA must be disabled. Additionally, the account security must be lowered by removing this option:

![option](./images/google-account-less-secure-prompt.PNG)

### Puppeteer (required)

Make sure puppeteer is installed correctly by following google's guide [here](https://developers.google.com/web/tools/puppeteer/get-started)

### Package dependency install (required)

Install remaining dependencies:

```sh
npm install
```

In the `config/config.yml` section, the file shows what the config should look like. Additionally, if setting the email notification option to true, you must also configure `config/email_config.yml`

## Setting up config.yml

Most of the fields in the file are pretty self explanatory However, I will still make an effort to outline them.

**StepN:**

The `N` refers to which step of the form the selection is in. The example shown below is of `step1` of the ICBC form. Also notice that the options are indexed starting from 0 instead of 1.

![step1](./images/step1.PNG)

**Interval:**

The interval in *milliseconds* represents the amount of delay between each check on the ICBC website. Since we don't want to be hammering their service, it's best to leave this to 5 minutes.

**StartDate / EndDate:**

The start date to be searched through in `YYYY-MM-DD` format

**ShouldSendEmail:**

true / false value as a string indicating whether to send an email or not

## Usage

This program can be run in the background by simply running it with:

```sh
node app.js
```

## Suggestions

Feel free to let me know of any improvements you would like to see!

0 comments on commit 5a650ae

Please sign in to comment.