Add Cobot card fetching, cleanup config setup.

This commit is contained in:
Dana Woodman 2018-03-04 09:17:30 -08:00
parent a076724f83
commit bf358756e1
17 changed files with 173 additions and 28 deletions

11
.env.example Normal file
View File

@ -0,0 +1,11 @@
COBOT_CLIENT_ID='...'
COBOT_CLIENT_SECRET='...'
COBOT_REDIRECT_URL='http://10.0.1.48:8080/success'
COBOT_AUTHORIZE_URL='https://www.cobot.me/oauth/authorize'
COBOT_TOKEN_URL='https://www.cobot.me/oauth/access_token'
COBOT_SCOPE='checkin_tokens'
COBOT_USER_EMAIL='...'
COBOT_USER_PASSWORD='...'
COBOT_CARDS_API='https://chimera.cobot.me/api/check_in_tokens'
DOOR_OPEN_DELAY=6000
PORT=8080

11
.env.test Normal file
View File

@ -0,0 +1,11 @@
COBOT_CLIENT_ID='fake-id'
COBOT_CLIENT_SECRET='fake-secret'
COBOT_REDIRECT_URL='http://localhost:8080/success'
COBOT_AUTHORIZE_URL='https://www.cobot.me/oauth/authorize'
COBOT_TOKEN_URL='https://www.cobot.me/oauth/access_token'
COBOT_SCOPE='checkin_tokens'
COBOT_USER_EMAIL='info@chimeraarts.org'
COBOT_USER_PASSWORD='somepassword'
COBOT_CARDS_API='https://chimera.cobot.me/api/check_in_tokens'
DOOR_OPEN_DELAY=1
PORT=8080

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.env
node_modules node_modules
.DS_Store .DS_Store

View File

@ -4,4 +4,4 @@
# .tesselinclude works the same as .npminclude # .tesselinclude works the same as .npminclude
# You DO NOT need to list node_modules or package.json # You DO NOT need to list node_modules or package.json
# For more information, visit: https://tessel.io/docs/cli#usage # For more information, visit: https://tessel.io/docs/cli#usage
index.html .env

View File

@ -1,3 +0,0 @@
module.exports = {
env: 'ENV',
}

View File

@ -1,5 +0,0 @@
module.exports = {
cardApi: 'https://chimera.cobot.me/api/check_in_tokens',
env: 'development',
openDelay: 6000,
}

View File

@ -1,4 +0,0 @@
module.exports = {
env: 'test',
openDelay: 1,
}

5
package-lock.json generated
View File

@ -355,6 +355,11 @@
} }
} }
}, },
"dotenv": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
"integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow=="
},
"eslint": { "eslint": {
"version": "4.17.0", "version": "4.17.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.17.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.17.0.tgz",

View File

@ -8,15 +8,11 @@
"watch-test": "npm test -- --watch" "watch-test": "npm test -- --watch"
}, },
"dependencies": { "dependencies": {
"axios": "0.17.1", "axios": "0.18.0",
"chalk": "2.3.1", "chalk": "2.3.1",
"config": "1.30.0", "dotenv": "5.0.1",
"consolidate": "0.15.0",
"eslint": "4.17.0", "eslint": "4.17.0",
"express": "4.16.2",
"node-hid": "0.7.2", "node-hid": "0.7.2",
"pug": "2.0.0-rc.4",
"serialport": "6.0.5",
"tessel": "0.3.25" "tessel": "0.3.25"
}, },
"devDependencies": { "devDependencies": {

View File

@ -66,6 +66,10 @@ t2 erase
t2 ap -n doorlock t2 ap -n doorlock
``` ```
### Networking
To find the IP address of your Tessel, download the iOS app Fing and look for a device on your network called `doorlock`.
### USB Storage ### USB Storage
* Make sure to format USB to be FAT32! * Make sure to format USB to be FAT32!

View File

@ -1,6 +1,19 @@
const Door = require('./models/door') const Cobot = require('./models/cobot')
Door.open() Cobot.authorize().then(cobot => {
cobot.cards().then(resp => console.log('RESP:', resp))
})
// const server = require('./server')
// server()
// const Cards = require('./models/cards')
// const Door = require('./models/door')
// Door.open()
// Cards.update()
// const server = require('./server') // const server = require('./server')

14
src/constants.js Normal file
View File

@ -0,0 +1,14 @@
require('dotenv').config()
const ENV = process.env.NODE_ENV || 'development'
module.exports = {
COBOT_CARDS_API: process.env.COBOT_CARDS_API,
COBOT_CLIENT_ID: process.env.COBOT_CLIENT_ID,
COBOT_CLIENT_SECRET: process.env.COBOT_CLIENT_SECRET,
COBOT_SCOPE: process.env.COBOT_SCOPE,
COBOT_USER_EMAIL: process.env.COBOT_USER_EMAIL,
COBOT_USER_PASSWORD: process.env.COBOT_USER_PASSWORD,
DOOR_OPEN_DELAY: process.env.DOOR_OPEN_DELAY,
ENV,
}

View File

@ -1,9 +1,9 @@
const axios = require('axios') const axios = require('axios')
const config = require('config') const { COBOT_CARDS_API } = require('../constants')
class Cards { class Cards {
static update() { static update() {
return axios.get(config.get('cardApi')) return axios.get(COBOT_CARDS_API)
} }
} }

64
src/models/cobot.js Normal file
View File

@ -0,0 +1,64 @@
const axios = require('axios')
const {
COBOT_CARDS_API,
COBOT_CLIENT_ID,
COBOT_CLIENT_SECRET,
COBOT_SCOPE,
COBOT_USER_EMAIL,
COBOT_USER_PASSWORD,
} = require('../constants')
class Cobot {
constructor(token) {
this.token = token
}
cards() {
if (!COBOT_CARDS_API)
throw new Error('missing "COBOT_CARDS_API" env variable!')
return axios
.get(COBOT_CARDS_API, {
headers: {
Authorization: `Bearer ${this.token}`,
},
})
.then(resp =>
resp.data.map(card => ({
name: card.membership.name,
number: card.token,
}))
)
}
static authorize() {
if (!COBOT_SCOPE) throw new Error('missing "COBOT_SCOPE" env variable!')
if (!COBOT_USER_EMAIL)
throw new Error('missing "COBOT_USER_EMAIL" env variable!')
if (!COBOT_USER_PASSWORD)
throw new Error('missing "COBOT_USER_PASSWORD" env variable!')
if (!COBOT_CLIENT_ID)
throw new Error('missing "COBOT_CLIENT_ID" env variable!')
if (!COBOT_CLIENT_SECRET)
throw new Error('missing "COBOT_CLIENT_SECRET" env variable!')
console.log(
COBOT_SCOPE,
COBOT_USER_EMAIL,
COBOT_USER_PASSWORD,
COBOT_CLIENT_ID,
COBOT_CLIENT_SECRET
)
const qs = [
`scope=${COBOT_SCOPE}`,
`grant_type=password`,
`username=${COBOT_USER_EMAIL}`,
`password=${COBOT_USER_PASSWORD}`,
`client_id=${COBOT_CLIENT_ID}`,
`client_secret=${COBOT_CLIENT_SECRET}`,
].join('&')
return axios
.post(`https://www.cobot.me/oauth/access_token?${qs}`)
.then(resp => new Cobot(resp.data.access_token))
}
}
module.exports = Cobot

41
src/models/cobot.test.js Normal file
View File

@ -0,0 +1,41 @@
const axios = require('axios')
const Cobot = require('./cobot')
jest.mock('axios')
describe('models/cobot', () => {
describe('.authorize', () => {
test('should fetch a new token', () => {
const resp = { data: { access_token: 'meow' } }
jest.spyOn(axios, 'post').mockResolvedValue(resp)
return Cobot.authorize().then(cobot => {
expect(axios.post).toBeCalled()
expect(cobot).toBeInstanceOf(Cobot)
expect(cobot.token).toBe('meow')
})
})
})
describe('.cards', () => {
test('returns a structured list of cards', () => {
const resp = {
data: [
{ membership: { id: 'foo', name: 'John' }, token: '001' },
{ membership: { id: 'bar', name: 'Jane' }, token: '002' },
],
}
const expected = [
{ name: 'John', number: '001' },
{ name: 'Jane', number: '002' },
]
jest.spyOn(axios, 'get').mockResolvedValue(resp)
// TODO: why doesnt this work? It should...
// axios.get.mockResolvedValue(resp)
return new Cobot('fake-value')
.cards()
.then(actual => expect(actual).toEqual(expected))
})
})
})

View File

@ -1,9 +1,7 @@
const config = require('config') const { DOOR_OPEN_DELAY } = require('../constants')
const logger = require('../utils/logger') const logger = require('../utils/logger')
const tessel = require('tessel') const tessel = require('tessel')
const DOOR_OPEN_DELAY = config.get('openDelay')
// const fs = require('fs') // const fs = require('fs')
// const path = require('path') // const path = require('path')

View File

@ -1,5 +1,4 @@
const config = require('config') const { ENV } = require('../constants')
const ENV = config.get('env')
class Logger { class Logger {
log() { log() {