Skip to content

Latest commit

 

History

History
205 lines (138 loc) · 6.99 KB

README.md

File metadata and controls

205 lines (138 loc) · 6.99 KB

unwaitlist

Gotta scrape 'n send that waitlist! Allowing University of Vermont students to subscribe for notification of when their course of interest has availability.

Setup

Install NPM packages

npm i require axios nodemailer twilio dotenv googleapis@39 google-spreadsheet

Add .env file

With config info for twilio

# email creds
EMAIL_USER=youemail@domain.com
EMAIL_PASS=***

# twilio auth
TWILIO_SID=***
TWILIO_TOKEN=***

# g-sheets auth
type=***
project_id=***
private_key_id=***
private_key=-----BEGIN PRIVATE KEY-----\***\n-----END PRIVATE KEY-----\n
client_email=***
client_id=***
auth_uri=https://accounts.google.com/o/oauth2/auth
token_uri=https://oauth2.googleapis.com/token
auth_provider_x509_cert_url=https://www.googleapis.com/oauth2/v1/certs
client_x509_cert_url=***

Run

npm run unwait

Once Semester Maintenance

  • Update all link pre-fixes that get sent to users via email. Based off UVM's public facing course catalog.
  • Update the link to the registrar's page.
  • Make sure Twilio has sufficient funds to continue messaging users
  • Download the current courses (either fall or spring) as an Excel file (or use text-splitting in gSheets). Then copy/paste them into the Course Data tab of the Google Spreadsheet.

Project Resource Catalog

TODO

Issues requiring immediate attention are flagged in the code by "TODO"

  • List all classes being checked each time user requests another course. For example, if their third request was phil, the follow-up email would confirm phil and list the other two pending courses.
  • On initial request, check if the course has other cross listed CRNs that also should be getting checked.

Azure Functions: free, cloud-based execution

NodeMailer: email

Twilio: web-based phone calls

Axios: webpage loading

  • make promise based http requests
  • won't render any javascript based changes

dotenv: protecting sensitive variables

Google Sheets API: user management

Sheets Setup

  • Online, visit the Google Dev Console and create a service worker
  • Share your spreadsheet with the service worker's email
  • Here's a Google Spreadsheet for testing: this google sheet

Usage

  • Reading can be done by cells or rows, but rows seems to make the context more easily understood
  • Writing is done simply with the assignment operator to a given cell, but this must be followed by row.save()
  • Caution: don't fully understand this, but it seems to ensure a save ONLY when it is the last statement to be evaluated in a function. You can force a save to happen immediately with await promisify(row.save)() instead of row.save(). My experience otherwise has been that it will end the function wherever you call promisify from.

Code Styles / Conventions

Decrease Cyclomatic Complexity

  • Cyclomatic Complexity - number of different possible paths, level of nesting, indentation

Example Good: Cyclomatic Complexity = 1 (with Early Termination (ET))

if (!someCondition) return
if (!newCondition) return
if (!nextCondition) return
// do something

Example Bad: Cyclomatic Complexity = 3

if (someCondition) {
    if (newCondition) {
        if (nextCondition) {
            // do something
        }
    }
}

Scope based naming

  • Variable name length can get smaller as you limit the scope of that variable

Example:

cosnt USER_ROW_INFO = ""
let row = allRows.find(r => r.id === ID)

JavaScript Brackets

For guarded if statements, use brackets (just as style convention)

if (!duplicateRow) return true      // bad
if (!duplicateRow) { return true }  // good

Avoid Yoda Conditions

Try to place the target of the investigation as the first term/expression in a comparison operator

  • Good: x === 7 - reads as "Does 'x' equal 7?"

  • Bad: 7 === x - reads as "Does 7 equal x?"

Frame Booleans Affirmatively

  • Boolean Values should always be verb questions that have yes/no answer (ex. isRegNumInvalid)
    • Preference for interpretation should be default is false
    • State things in the affirmative ex. prefer IsTrue to IsUntrue

JavaScript Array Examples

var array = [{compnum: "13113"}, {compnum: "45345"}, {compnum: "34534"}]

// map values in array to return processed value for each item
array.map(i => i.compnum)

// filter list of values to matching criteria
array.filter(i => i.compnum === "45345")

// filter list of values to matching criteria - but just find the first record - return record
array.find(i => i.compnum === "45345")

// see if any values in array meet criteria
array.some(i => i.compnum === "45345")