├── .gitignore ├── CODE_OF_CONDUCT.md ├── deployment ├── run-unit-tests.sh └── build-s3-dist.sh ├── source ├── services │ ├── jitr │ │ ├── test-setup.spec.js │ │ ├── package.json │ │ └── index.js │ ├── driversafety │ │ ├── package.json │ │ ├── lib │ │ │ ├── index.js │ │ │ ├── driver-safety.spec.js │ │ │ └── driver-safety.js │ │ └── index.js │ ├── notification │ │ ├── package.json │ │ ├── lib │ │ │ ├── index.js │ │ │ ├── notification.js │ │ │ └── notification.spec.js │ │ └── index.js │ ├── vehicle │ │ ├── package.json │ │ ├── index.js │ │ └── lib │ │ │ ├── vehicle.spec.js │ │ │ ├── vehicle.js │ │ │ ├── anomaly.spec.js │ │ │ ├── healthreport.spec.js │ │ │ ├── trip.spec.js │ │ │ ├── dtc.spec.js │ │ │ ├── trip.js │ │ │ ├── healthreport.js │ │ │ ├── dtc.js │ │ │ ├── anomaly.js │ │ │ └── index.js │ ├── anomaly │ │ ├── package.json │ │ ├── index.js │ │ └── lib │ │ │ └── index.js │ ├── dtc │ │ ├── package.json │ │ ├── lib │ │ │ ├── index.js │ │ │ └── dtc.spec.js │ │ └── index.js │ └── marketing │ │ ├── package.json │ │ ├── lib │ │ ├── index.js │ │ ├── marketing.spec.js │ │ └── marketing.js │ │ └── index.js ├── data-loaders │ └── dtc-generator │ │ ├── package.json │ │ ├── index.js │ │ └── loader.js └── resources │ └── helper │ ├── package.json │ ├── marketing-pois.csv │ ├── obd-trouble-codes.csv │ └── lib │ ├── metrics-helper.js │ ├── iot-helper.js │ └── dynamodb-helper.js ├── CHANGELOG.md ├── NOTICE.txt ├── README.md ├── CONTRIBUTING.md └── LICENSE.txt /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/dist 3 | **/open-source 4 | **/.zip 5 | **/.DS_Store 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. -------------------------------------------------------------------------------- /deployment/run-unit-tests.sh: -------------------------------------------------------------------------------- 1 | cd ../source/services/anomaly 2 | npm install 3 | npm test 4 | 5 | cd ../driversafety 6 | npm install 7 | npm test 8 | 9 | cd ../dtc 10 | npm install 11 | npm test 12 | 13 | cd ../notification 14 | npm install 15 | npm test 16 | 17 | cd ../vehicle 18 | npm install 19 | npm test 20 | 21 | cd ../marketing 22 | npm install 23 | npm test 24 | -------------------------------------------------------------------------------- /source/services/jitr/test-setup.spec.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon'); 2 | const chai = require('chai'); 3 | const sinonChai = require('sinon-chai'); 4 | 5 | before(function() { 6 | chai.use(sinonChai); 7 | }); 8 | 9 | beforeEach(function() { 10 | this.sandbox = sinon.sandbox.create(); 11 | }); 12 | 13 | afterEach(function() { 14 | this.sandbox.restore(); 15 | }); 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [2.1.2] - 2021-05-31 9 | 10 | ### Added 11 | 12 | - Added Point In Time recovery and Encryption support for DynamoDB Table 13 | - Added API Gateway usage plan 14 | - Added cfn_nag suppress rules for Lambda VPC deployment and Reserved Concurrency 15 | 16 | ### Fixed 17 | 18 | - Removed unused dev dependency grunt 19 | 20 | ## [2.1.1] - 2019-12-20 21 | 22 | ### Added 23 | 24 | - upgraded lambda runtime to nodejs 12.x 25 | -------------------------------------------------------------------------------- /source/data-loaders/dtc-generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connected-car-sim-engine", 3 | "description": "The simulation engine for the connected car solutions", 4 | "main": "index.js", 5 | "license": "ASL", 6 | "version": "0.0.1", 7 | "private": "true", 8 | "dependencies": { 9 | "aws-sdk": "*", 10 | "aws-iot-device-sdk": "*", 11 | "moment": "*", 12 | "randomstring": "*", 13 | "shortid": "*", 14 | "underscore": "*" 15 | }, 16 | "devDependencies": {}, 17 | "scripts": { 18 | "prestart": "npm install", 19 | "start": "node ./", 20 | "pretest": "npm install", 21 | "test": "karma start karma.conf.js", 22 | "test-single-run": "karma start karma.conf.js --single-run" 23 | }, 24 | "bundledDependencies": [] 25 | } 26 | -------------------------------------------------------------------------------- /source/services/jitr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-vehicle-jitr", 3 | "description": "A Lambda function for the vehicle just-in-time-registration microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*" 12 | }, 13 | "devDependencies": { 14 | "chai": "*", 15 | "sinon": "*", 16 | "sinon-chai": "*", 17 | "mocha": "*", 18 | "aws-sdk-mock": "*", 19 | "npm-run-all": "*", 20 | "proxyquire": "*" 21 | }, 22 | "scripts": { 23 | "pretest": "npm install", 24 | "test": "mocha *.spec.js", 25 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist", 26 | "build:copy": "cp index.js dist/", 27 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 28 | "build": "npm-run-all -s build-init build:copy build:install", 29 | "zip": "cd dist && zip -rq vhr-vehicle-jitr.zip ." 30 | }, 31 | "bundledDependencies": [] 32 | } 33 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | AWS Connected Vehicle Solution 2 | 3 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | Licensed under the Apache License Version 2.0 (the "License"). You may not use this file except 5 | in compliance with the License. A copy of the License is located at http://www.apache.org/licenses/ 6 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, 7 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. See the License for the 8 | specific language governing permissions and limitations under the License. 9 | 10 | ********************** 11 | THIRD PARTY COMPONENTS 12 | ********************** 13 | This software includes third party software subject to the following copyrights: 14 | 15 | AWS SDK under the Apache License Version 2.0 16 | Underscore.js under the Massachusetts Institute of Technology (MIT) license 17 | Moment.js under the Massachusetts Institute of Technology (MIT) license 18 | shortid under the Massachusetts Institute of Technology (MIT) license 19 | randomstring under the Massachusetts Institute of Technology (MIT) license 20 | 21 | The licenses for these third party components are included in LICENSE.txt 22 | -------------------------------------------------------------------------------- /source/resources/helper/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-framework-helper", 3 | "description": "UI Framework custom resource helper Lambda function", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "moment": "*", 13 | "underscore": "*", 14 | "node-uuid": "*", 15 | "fast-csv": "*" 16 | }, 17 | "devDependencies": { 18 | "chai": "*", 19 | "sinon": "*", 20 | "sinon-chai": "*", 21 | "mocha": "*", 22 | "aws-sdk-mock": "*", 23 | "npm-run-all": "*" 24 | }, 25 | "scripts": { 26 | "pretest": "npm install", 27 | "test": "mocha lib/*.spec.js", 28 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 29 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 30 | "build:install": "cp package.json dist/ && cp *.csv dist/ && cd dist && npm install --production", 31 | "build": "npm-run-all -s build-init build:copy build:install", 32 | "zip": "cd dist && zip -rq cv-deployment-helper.zip ." 33 | }, 34 | "bundledDependencies": [ 35 | "moment", 36 | "underscore", 37 | "node-uuid", 38 | "fast-csv" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /source/services/driversafety/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-dtc-service", 3 | "description": "A Lambda function for the vehicle health report diagnostic trouble code microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "moment": "*", 13 | "shortid": "*", 14 | "underscore": "*" 15 | }, 16 | "devDependencies": { 17 | "aws-sdk-mock": "*", 18 | "chai": "*", 19 | "mocha": "*", 20 | "npm-run-all": "*", 21 | "proxyquire": "*", 22 | "sinon": "*", 23 | "sinon-chai": "*" 24 | }, 25 | "scripts": { 26 | "pretest": "npm install", 27 | "test": "env DTC_TBL='dtc' mocha lib/*.spec.js", 28 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 29 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 30 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 31 | "build": "npm-run-all -s build-init build:copy build:install", 32 | "zip": "cd dist && zip -rq vhr-driver-safety-service.zip ." 33 | }, 34 | "bundledDependencies": [ 35 | "moment", 36 | "shortid", 37 | "underscore" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /source/services/notification/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-notification-service", 3 | "description": "A Lambda function for the vehicle health report notification microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "moment": "*", 13 | "shortid": "*", 14 | "underscore": "*" 15 | }, 16 | "devDependencies": { 17 | "aws-sdk-mock": "*", 18 | "chai": "*", 19 | "mocha": "*", 20 | "npm-run-all": "*", 21 | "proxyquire": "*", 22 | "sinon": "*", 23 | "sinon-chai": "*" 24 | }, 25 | "scripts": { 26 | "pretest": "npm install", 27 | "test": "env VEHICLE_OWNER_TBL='vehicle_tbl' USER_POOL_ID='userpool' mocha lib/*.spec.js", 28 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 29 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 30 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 31 | "build": "npm-run-all -s build-init build:copy build:install", 32 | "zip": "cd dist && zip -rq vhr-notification-service.zip ." 33 | }, 34 | "bundledDependencies": [ 35 | "moment", 36 | "shortid", 37 | "underscore" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /source/services/vehicle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-vehicle-service", 3 | "description": "A Lambda function for the vehicle microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "moment": "*", 13 | "shortid": "*", 14 | "underscore": "*" 15 | }, 16 | "devDependencies": { 17 | "aws-sdk-mock": "*", 18 | "chai": "*", 19 | "mocha": "*", 20 | "npm-run-all": "*", 21 | "proxyquire": "*", 22 | "sinon": "*", 23 | "sinon-chai": "*" 24 | }, 25 | "scripts": { 26 | "pretest": "npm install", 27 | "test": "env VEHICLE_ANOMALY_TBL='tblanomaly' VEHICLE_OWNER_TBL='tblowner' HEALTH_REPORT_TBL='tblhealthreport' mocha lib/*.spec.js", 28 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 29 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 30 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 31 | "build": "npm-run-all -s build-init build:copy build:install", 32 | "zip": "cd dist && zip -rq vhr-vehicle-service.zip ." 33 | }, 34 | "bundledDependencies": [ 35 | "moment", 36 | "shortid", 37 | "underscore" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /source/services/anomaly/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-anomaly-service", 3 | "description": "A Lambda function for the vehicle anomaly microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "moment": "*", 13 | "randomstring": "*", 14 | "shortid": "*", 15 | "underscore": "*" 16 | }, 17 | "devDependencies": { 18 | "aws-sdk-mock": "*", 19 | "chai": "*", 20 | "mocha": "*", 21 | "npm-run-all": "*", 22 | "proxyquire": "*", 23 | "sinon": "*", 24 | "sinon-chai": "*" 25 | }, 26 | "scripts": { 27 | "pretest": "npm install", 28 | "test": "env VEHICLE_ANOMALY_TBL='anomalytable' NOTIFICATION_SERVICE='notifyservice' mocha lib/*.spec.js", 29 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 30 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 31 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 32 | "build": "npm-run-all -s build-init build:copy build:install", 33 | "zip": "cd dist && zip -rq vhr-anomaly-service.zip ." 34 | }, 35 | "bundledDependencies": [ 36 | "moment", 37 | "shortid", 38 | "underscore" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /source/services/dtc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-dtc-service", 3 | "description": "A Lambda function for the vehicle dtc microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "moment": "*", 13 | "randomstring": "*", 14 | "shortid": "*", 15 | "underscore": "*" 16 | }, 17 | "devDependencies": { 18 | "aws-sdk-mock": "*", 19 | "chai": "*", 20 | "mocha": "*", 21 | "npm-run-all": "*", 22 | "proxyquire": "*", 23 | "sinon": "*", 24 | "sinon-chai": "*" 25 | }, 26 | "scripts": { 27 | "pretest": "npm install", 28 | "test": "env VEHICLE_TRIP_TBL='triptable' DTC_TBL='dtctable' NOTIFICATION_SERVICE='notifyservice' mocha lib/*.spec.js", 29 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 30 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 31 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 32 | "build": "npm-run-all -s build-init build:copy build:install", 33 | "zip": "cd dist && zip -rq vhr-dtc-service.zip ." 34 | }, 35 | "bundledDependencies": [ 36 | "moment", 37 | "shortid", 38 | "underscore" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /source/services/marketing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhr-marketing-service", 3 | "description": "A Lambda function for the location-based marketing microservice", 4 | "main": "index.js", 5 | "author": { 6 | "name": "aws-solutions-builder" 7 | }, 8 | "version": "0.0.1", 9 | "private": "true", 10 | "dependencies": { 11 | "aws-sdk": "*", 12 | "geolib": "*", 13 | "moment": "*", 14 | "underscore": "*" 15 | }, 16 | "devDependencies": { 17 | "aws-sdk-mock": "*", 18 | "chai": "*", 19 | "mocha": "*", 20 | "npm-run-all": "*", 21 | "proxyquire": "*", 22 | "sinon": "*", 23 | "sinon-chai": "*" 24 | }, 25 | "scripts": { 26 | "pretest": "npm install", 27 | "test": "env MKT_TBL='AdTrackingTable' POI_TBL='MarketingPoiTable' NOTIFICATION_SERVICE='notifyservice' mocha lib/*.spec.js", 28 | "build-init": "rm -rf dist && rm -f archive.zip && mkdir dist && mkdir dist/lib", 29 | "build:copy": "cp index.js dist/ && cp -r lib/*.js dist/lib", 30 | "build:install": "cp package.json dist/ && cd dist && npm install --production", 31 | "build": "npm-run-all -s build-init build:copy build:install", 32 | "zip": "cd dist && zip -rq vhr-marketing-service.zip ." 33 | }, 34 | "bundledDependencies": [ 35 | "moment", 36 | "geolib", 37 | "underscore" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /source/resources/helper/marketing-pois.csv: -------------------------------------------------------------------------------- 1 | va_rst_5,"11900 Market St, Reston, VA 20190",Reston,38.958439,-77.357138,Happy hour every weekday from 4-7pm. $2 off drinks and food,Dave's,500,VA 2 | va_rst_4,"12200 Sunset Hills Rd, Reston, VA 20190",Reston,38.954541,-77.366502,Show this message for free cornbread w/ purchase of any meal,Chris' Famous BBQ,500,VA 3 | va_rst_3,"770 Elden St, Herndon, VA 20170",Herndon,38.969389,-77.386678,Now serving breakfast!,Sean's Place,500,VA 4 | va_rst_2,"1200 Elden St, Herndon, VA 20170",Herndon,38.967435,-77.396295,Open Mon-Sun 11am-10pm. Check out our menu:,Herndon Tacos,500,VA 5 | va_rst_1,"14000 Parcher Ave, Herndon, VA 20170",Herndon,38.95934,-77.403683,Book your holiday party and get a $50 gift card:,The Bar,500,VA 6 | va_ret_3,"2500 McNair Farms Dr, Herndon, VA 20171",Herndon,38.94567,-77.408112,Free oil change this month,Herndon Car Repair,500,VA 7 | va_ret_2,"1700 Reston Pkwy, Reston, VA 20194",Reston,38.968398,-77.354168,Huge discounts on last season's items:,Reston Home Store,500,VA 8 | va_ret_1,"400 Elden St, Herndon, VA 20170",Herndon,38.96679,-77.376669,Find over $300 in savings with this week's deals:,Herndon Grocery,500,VA 9 | va_rec_1,"11800 Sunrise Valley Dr, Reston, VA 20191",Reston,38.943114,-77.352458,Don't forget to register for the the town 5k this weekend!,Reston Town Park,500,VA 10 | va_edu_1,"700 Dranesville Rd, Herndon, VA 20170",Herndon,38.97674,-77.377427,"Parents, don't forget, no school this Friday. Enjoy your long weekend!",Town High School,500,VA 11 | ,,,,,,,, -------------------------------------------------------------------------------- /source/resources/helper/obd-trouble-codes.csv: -------------------------------------------------------------------------------- 1 | "P0100","Mass or Volume Air Flow Circuit Malfunction" 2 | "P0101","Mass or Volume Air Flow Circuit Range/Performance Problem" 3 | "P0102","Mass or Volume Air Flow Circuit Low Input" 4 | "P0103","Mass or Volume Air Flow Circuit High Input" 5 | "P0104","Mass or Volume Air Flow Circuit Intermittent" 6 | "P0105","Manifold Absolute Pressure/Barometric Pressure Circuit Malfunction" 7 | "P0106","Manifold Absolute Pressure/Barometric Pressure Circuit Range/Performance Problem" 8 | "P0107","Manifold Absolute Pressure/Barometric Pressure Circuit Low Input" 9 | "P0108","Manifold Absolute Pressure/Barometric Pressure Circuit High Input" 10 | "P0109","Manifold Absolute Pressure/Barometric Pressure Circuit Intermittent" 11 | "P0110","IAT Circuit Malfunction" 12 | "P0111","Intake Air Temperature Circuit Range/Performance Problem" 13 | "P0112","Intake Air Temperature Circuit Low Input" 14 | "P0113","Intake Air Temperature Circuit High Input" 15 | "P0114","Intake Air Temperature Circuit Intermittent" 16 | "P0115","Engine Coolant Temperature Circuit Malfunction" 17 | "P0116","Engine Coolant Temperature Circuit Range/Performance Problem" 18 | "P0117","Engine Coolant Temperature Circuit Low Input" 19 | "P0118","Engine Coolant Temperature Circuit High Input" 20 | "P0119","Engine Coolant Temperature Circuit Intermittent" 21 | "P0120","Throttle Position Sensor/Switch A Circuit Malfunction" 22 | "P0121","Throttle Position Sensor/Switch A Circuit Range/Performance Problem" 23 | "P0122","Throttle Position Sensor/Switch A Circuit Low Input" 24 | "P0123","Throttle Position Sensor/Switch A Circuit High Input" 25 | "P0124","Throttle Position Sensor/Switch A Circuit Intermittent" 26 | "P0125","Insufficient Coolant Temperature for Closed Loop Fuel Control;" 27 | "P0126","ECT Excessive Time to Closed Loop Fuel Control" 28 | "P0128","Insufficient Coolant Temperature for Stable Operation" 29 | "P0130","Coolant Thermostat Malfunction" 30 | -------------------------------------------------------------------------------- /source/services/marketing/lib/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let AWS = require('aws-sdk'); 21 | let advertisement = require('./marketing.js'); 22 | 23 | module.exports.respond = function(event, cb) { 24 | 25 | let _ad = new advertisement(); 26 | _ad.getPoints(event, function(err, data) { 27 | if (err) { 28 | return cb(err, null); 29 | } 30 | 31 | return cb(null, data); 32 | }); 33 | 34 | }; 35 | -------------------------------------------------------------------------------- /source/services/driversafety/lib/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let AWS = require('aws-sdk'); 21 | let DriverSafety = require('./driver-safety.js'); 22 | 23 | module.exports.respond = function(event, cb) { 24 | 25 | // get predication and store results 26 | let _driverSafety = new DriverSafety(); 27 | _driverSafety.getDriverScorePrediction(event, function(err, data) { 28 | if (err) { 29 | console.log(err); 30 | return cb(err, null); 31 | } 32 | 33 | return cb(null, data); 34 | }); 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /source/services/notification/lib/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let AWS = require('aws-sdk'); 21 | let Notification = require('./notification.js'); 22 | 23 | module.exports.respond = function(event, cb) { 24 | 25 | // get predication and store results 26 | let _notification = new Notification(); 27 | _notification.sendNotiviationViaMqtt(event, function(err, mdata) { 28 | if (err) { 29 | console.log(err); 30 | } 31 | 32 | _notification.sendNotification(event, function(err, data) { 33 | if (err) { 34 | console.log(err); 35 | return cb(err, null); 36 | } 37 | 38 | return cb(null, data); 39 | }); 40 | 41 | }); 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /source/services/dtc/lib/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let AWS = require('aws-sdk'); 21 | let Dtc = require('./dtc.js'); 22 | 23 | module.exports.respond = function(event, cb) { 24 | 25 | let _dtc = new Dtc(); 26 | let _message = {}; 27 | 28 | if (typeof event === 'object') { 29 | _message = event; 30 | } else { 31 | _message = JSON.parse(event); 32 | } 33 | 34 | if (event.action) { 35 | 36 | } else if (event.timestamp && event.value) { 37 | // identify message as dtc object to be created from IoT platform 38 | _dtc.createDtc(event, function(err, data) { 39 | if (err) { 40 | return cb(err, null); 41 | } 42 | 43 | return cb(null, data); 44 | }); 45 | } 46 | 47 | }; 48 | -------------------------------------------------------------------------------- /source/services/dtc/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | console.log('Loading function'); 21 | let lib = require('./lib'); 22 | 23 | exports.handler = function(event, context, callback) { 24 | // Load the message passed into the Lambda function into a JSON object 25 | var eventText = JSON.stringify(event, null, 2); 26 | 27 | // Log a message to the console, you can view this text in the Monitoring tab in the Lambda console 28 | // or in the CloudWatch Logs console 29 | console.log('Received event:', eventText); 30 | 31 | lib.respond(event, function(error, response) { 32 | if (error) { 33 | console.error(error); 34 | return callback(null, error); 35 | } else { 36 | return callback(null, response); 37 | } 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /source/services/anomaly/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | console.log('Loading function'); 21 | let lib = require('./lib'); 22 | 23 | exports.handler = function(event, context, callback) { 24 | // Load the message passed into the Lambda function into a JSON object 25 | var eventText = JSON.stringify(event, null, 2); 26 | 27 | // Log a message to the console, you can view this text in the Monitoring tab in the Lambda console 28 | // or in the CloudWatch Logs console 29 | console.log('Received event:', eventText); 30 | 31 | lib.respond(event, function(error, response) { 32 | if (error) { 33 | console.error(error); 34 | return callback(null, error); 35 | } else { 36 | return callback(null, response); 37 | } 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /source/services/vehicle/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | console.log('Loading function'); 21 | let lib = require('./lib'); 22 | 23 | exports.handler = function(event, context, callback) { 24 | // Load the message passed into the Lambda function into a JSON object 25 | var eventText = JSON.stringify(event, null, 2); 26 | 27 | // Log a message to the console, you can view this text in the Monitoring tab in the Lambda console 28 | // or in the CloudWatch Logs console 29 | console.log('Received event:', eventText); 30 | 31 | lib.respond(event, function(error, response) { 32 | if (error) { 33 | console.error(error); 34 | return callback(null, error); 35 | } else { 36 | return callback(null, response); 37 | } 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /source/services/driversafety/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | console.log('Loading function'); 21 | let lib = require('./lib'); 22 | 23 | exports.handler = function(event, context, callback) { 24 | // Load the message passed into the Lambda function into a JSON object 25 | var eventText = JSON.stringify(event, null, 2); 26 | 27 | // Log a message to the console, you can view this text in the Monitoring tab in the Lambda console 28 | // or in the CloudWatch Logs console 29 | console.log('Received event:', eventText); 30 | 31 | lib.respond(event, function(error, response) { 32 | if (error) { 33 | console.error(error); 34 | return callback(null, error); 35 | } else { 36 | return callback(null, response); 37 | } 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /source/services/marketing/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | console.log('Loading function'); 21 | let lib = require('./lib'); 22 | 23 | exports.handler = function(event, context, callback) { 24 | // Load the message passed into the Lambda function into a JSON object 25 | var eventText = JSON.stringify(event, null, 2); 26 | 27 | // Log a message to the console, you can view this text in the Monitoring tab in the Lambda console 28 | // or in the CloudWatch Logs console 29 | console.log('Received event:', eventText); 30 | 31 | lib.respond(event, function(error, response) { 32 | if (error) { 33 | console.error(error); 34 | return callback(null, error); 35 | } else { 36 | return callback(null, response); 37 | } 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /source/services/notification/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | console.log('Loading function'); 21 | let lib = require('./lib'); 22 | 23 | exports.handler = function(event, context, callback) { 24 | // Load the message passed into the Lambda function into a JSON object 25 | var eventText = JSON.stringify(event, null, 2); 26 | 27 | // Log a message to the console, you can view this text in the Monitoring tab in the Lambda console 28 | // or in the CloudWatch Logs console 29 | console.log('Received event:', eventText); 30 | 31 | lib.respond(event, function(error, response) { 32 | if (error) { 33 | console.error(error); 34 | return callback(null, error); 35 | } else { 36 | return callback(null, response); 37 | } 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /source/services/anomaly/lib/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let AWS = require('aws-sdk'); 21 | let Anomaly = require('./anomaly.js'); 22 | 23 | module.exports.respond = function(event, cb) { 24 | 25 | let _anomaly = new Anomaly(); 26 | let _message = {}; 27 | 28 | if (typeof event === 'object') { 29 | _message = event; 30 | } else { 31 | _message = JSON.parse(event); 32 | } 33 | 34 | if (event.action) { 35 | 36 | } else { 37 | let payload = new Buffer(event.Records[0].kinesis.data, 'base64').toString('ascii'); 38 | console.log('Decoded payload:', payload); 39 | let _record = JSON.parse(payload); 40 | // identify message as dtc object to be created from IoT platform 41 | _anomaly.createAnomaly(_record, function(err, data) { 42 | if (err) { 43 | return cb(err, null); 44 | } 45 | 46 | return cb(null, data); 47 | }); 48 | } 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /source/services/marketing/lib/marketing.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let advertisement = require('./marketing.js'); 10 | 11 | describe('advertisement', function() { 12 | 13 | let payload = { 14 | timestamp: '2017-12-19 18:10:46.836000000', 15 | trip_id: '59a84da4-0c17-4f6c-9405-8187dc1af3e5', 16 | vin: 'SAMPLEVIN123', 17 | name: 'location', 18 | latitude: '-12.34567', 19 | longitude: '98.76543' 20 | }; 21 | 22 | let poiRecord = { 23 | city: 'Henderson', 24 | poi_id: 'nv_rec_2', 25 | radius: '500', 26 | longitude: '-115.024756', 27 | message: 'Closed for Winter. Save on 2018 season passes:', 28 | address: '900 Galleria Dr, Henderson, NV 89011', 29 | poi: 'Cowabunga Bay Las Vegas', 30 | latitude: '36.072018', 31 | state: 'NV' 32 | }; 33 | 34 | describe('#getPoints', function() { 35 | 36 | beforeEach(function() {}); 37 | 38 | afterEach(function() { 39 | AWS.restore('DynamoDB.DocumentClient'); 40 | }); 41 | 42 | it('should return a list of POI records when ddb scan successful', function(done) { 43 | 44 | AWS.mock('DynamoDB.DocumentClient', 'scan', function(params, callback) { 45 | callback(null, { 46 | Items: [poiRecord] 47 | }); 48 | }); 49 | 50 | let _ad = new advertisement(); 51 | _ad.getPoints(payload, function(err, data) { 52 | if (err) done(err); 53 | else{ 54 | expect(data).to.equal('completed geo eval'); 55 | done(); 56 | } 57 | }); 58 | }); 59 | 60 | it('should return an error when ddb scan not successful', function(done) { 61 | 62 | AWS.mock('DynamoDB.DocumentClient', 'scan', function(params, callback) { 63 | callback('error',null); 64 | }); 65 | 66 | let _ad = new advertisement(); 67 | _ad.getPoints(payload, function(err, data) { 68 | if (err) { 69 | expect(err).to.equal('error'); 70 | done(); 71 | } else{ 72 | done(); 73 | } 74 | }); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /source/data-loaders/dtc-generator/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | const fs = require('fs'); 21 | let csv = require('fast-csv'); 22 | let fileStream = fs.createReadStream('./obd-trouble-codes.csv'); 23 | let parser = csv(); 24 | let codes = []; 25 | let codes_info = []; 26 | 27 | fileStream 28 | .on('readable', function() { 29 | var data; 30 | while ((data = fileStream.read()) !== null) { 31 | parser.write(data); 32 | } 33 | }) 34 | .on('end', function() { 35 | parser.end(); 36 | }); 37 | 38 | parser 39 | .on('readable', function() { 40 | var data; 41 | while ((data = parser.read()) !== null) { 42 | console.log(data); 43 | codes_info.push({ 44 | code: data[0], 45 | description: data[1] 46 | }); 47 | codes.push(data[0]); 48 | } 49 | }) 50 | .on('end', function() { 51 | console.log('done'); 52 | fs.writeFile('./dtc-info.js', JSON.stringify(codes_info), function(err) { 53 | if (err) { 54 | return console.log(err); 55 | } 56 | 57 | console.log('The file was saved!'); 58 | }); 59 | 60 | fs.writeFile('./diagnostic-trouble-codes.js', JSON.stringify(codes), function(err) { 61 | if (err) { 62 | return console.log(err); 63 | } 64 | 65 | console.log('The file was saved!'); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Connected Vehicle Solution 2 | The AWS Connected Vehicle Solution is a reference implementation that provides a foundation for automotive product transformations for connected vehicle services, autonomous driving, electric powertrains, and shared mobility. 3 | 4 | ## Getting Started 5 | To get started with the AWS Connected Vehicle Solution, please review the solution documentation. https://aws.amazon.com/answers/iot/connected-vehicle-solution/ 6 | 7 | ## Building distributables for customization 8 | * Configure the bucket name of your target Amazon S3 distribution bucket 9 | ``` 10 | export BUCKET_PREFIX=my-bucket-name 11 | ``` 12 | 13 | * Clone the repository, then build the distibutables: 14 | ``` 15 | cd ./deployment \n 16 | chmod +x build-s3-dist.sh \n 17 | ./build-s3-dist.sh \n 18 | ``` 19 | 20 | * Deploy the distibutables to an Amazon S3 bucket in your account. _Note:_ you must have the AWS Command Line Interface installed. 21 | 22 | ``` 23 | cd ./deployment \n 24 | s3 cp ./dist s3://my-bucket-name/aws-cv-solution/latest --recursive --profile aws-cred-profile-name \n 25 | ``` 26 | 27 | * Get the link of the aws-connected-vehicle-solution.template uploaded to your Amazon S3 bucket. 28 | * Deploy the AWS Connected Vehicle Solution to your account by launching a new AWS CloudFormation stack using the link of the aws-connected-vehicle-solution.template. 29 | 30 | ## File Structure 31 | The AWS Connected Vehicle Solution project consists of microservices that facilitate the functional areas of the platform. These microservices are deployed to a serverless environment in AWS Lambda. 32 | 33 |
34 | |-source/
35 |   |-services/
36 |     |-helper/       [ AWS CloudFormation custom resource deployment helper ]
37 |   |-services/
38 |     |-anomaly/      [ microservice for humanization and persistence of identified anomalies ]
39 |     |-driversafety/ [ microservice to orchestrate the creation of driver scores ]
40 |     |-dtc/          [ microservice to orchestrate the capture, humanization and persistence of diagnostic trouble codes ]
41 |     |-jitr/         [ microservice to orchestrate registration and policy creation for just-in-time registration of devices ]    
42 |     |-notification/ [ microservice to send SMS and MQTT notifications for the solution ]
43 |     |-vehicle/      [ microservice to provide proxy interface for the AWS Connected Vehicle Solution API ]    
44 | 
45 | 46 | Each microservice follows the structure of: 47 | 48 |
49 | |-service-name/
50 |   |-lib/
51 |     |-[ service module libraries and unit tests ]
52 |   |-index.js [ injection point for microservice ]
53 |   |-package.json
54 | 
55 | 56 | *** 57 | 58 | Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 59 | 60 | Licensed under the Amazon Software License (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at 61 | 62 | http://aws.amazon.com/asl/ 63 | 64 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and limitations under the License. 65 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/awslabs/aws-limit-monitor/issues), or [recently closed](https://github.com/awslabs/aws-limit-monitor/issues?q=is%3Aissue+is%3Aclosed), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Code of Conduct 44 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 45 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 46 | opensource-codeofconduct@amazon.com with any additional questions or comments. 47 | 48 | 49 | ## Security issue notifications 50 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 51 | 52 | 53 | ## Licensing 54 | 55 | See the [LICENSE](https://github.com/awslabs/aws-limit-monitor/blob/master/LICENSE.txt) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 56 | 57 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. -------------------------------------------------------------------------------- /source/data-loaders/dtc-generator/loader.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | const fs = require('fs'); 21 | let csv = require('fast-csv'); 22 | let parser = csv(); 23 | let codes_info = []; 24 | let AWS = require('aws-sdk'); 25 | 26 | const dynamoConfig = { 27 | region: 'us-east-1' 28 | }; 29 | const ddbTable = process.env.DTC_TABLE; 30 | 31 | let fileStream = fs.createReadStream('./obd-trouble-codes.csv'); 32 | fileStream 33 | .on('readable', function() { 34 | var data; 35 | while ((data = fileStream.read()) !== null) { 36 | parser.write(data); 37 | } 38 | }) 39 | .on('end', function() { 40 | parser.end(); 41 | }); 42 | 43 | parser 44 | .on('readable', function() { 45 | var data; 46 | while ((data = parser.read()) !== null) { 47 | console.log(data); 48 | codes_info.push({ 49 | dtc: data[0], 50 | description: data[1], 51 | steps: [] 52 | }); 53 | } 54 | }) 55 | .on('end', function() { 56 | console.log('done'); 57 | loadCodes(codes_info, 0, function(err, data) { 58 | if (err) { 59 | console.log(err); 60 | } else { 61 | console.log(data); 62 | } 63 | }); 64 | }); 65 | 66 | var loadCodes = function(items, index, cb) { 67 | if (index < items.length) { 68 | let params = { 69 | TableName: ddbTable, 70 | Item: items[index] 71 | }; 72 | 73 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 74 | docClient.put(params, function(err, data) { 75 | if (err) { 76 | console.log(err); 77 | } else { 78 | console.log(['Added DTC', params.Item.dtc].join(': ')); 79 | } 80 | 81 | index++; 82 | setTimeout(loadCodes, 100, items, index, cb); 83 | }); 84 | } else { 85 | return cb(null, 'All codes processed..'); 86 | } 87 | 88 | }; 89 | -------------------------------------------------------------------------------- /source/resources/helper/lib/metrics-helper.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let moment = require('moment'); 21 | let https = require('https'); 22 | 23 | /** 24 | * Helper function to interact with dynamodb for data lake cfn custom resource. 25 | * 26 | * @class metricsHelper 27 | */ 28 | let metricsHelper = (function() { 29 | 30 | /** 31 | * @class metricsHelper 32 | * @constructor 33 | */ 34 | let metricsHelper = function() {}; 35 | 36 | /** 37 | * Sends opt-in, anonymous metric. 38 | * @param {json} metric - metric to send to opt-in, anonymous collection. 39 | * @param {sendAnonymousMetric~requestCallback} cb - The callback that handles the response. 40 | */ 41 | metricsHelper.prototype.sendAnonymousMetric = function(metric, cb) { 42 | 43 | let _options = { 44 | hostname: 'metrics.awssolutionsbuilder.com', 45 | port: 443, 46 | path: '/generic', 47 | method: 'POST', 48 | headers: { 49 | 'Content-Type': 'application/json' 50 | } 51 | }; 52 | 53 | let request = https.request(_options, function(response) { 54 | // data is streamed in chunks from the server 55 | // so we have to handle the "data" event 56 | let buffer; 57 | let data; 58 | let route; 59 | 60 | response.on('data', function(chunk) { 61 | buffer += chunk; 62 | }); 63 | 64 | response.on('end', function(err) { 65 | data = buffer; 66 | cb(null, data); 67 | }); 68 | }); 69 | 70 | if (metric) { 71 | request.write(JSON.stringify(metric)); 72 | } 73 | 74 | request.end(); 75 | 76 | request.on('error', (e) => { 77 | console.error(e); 78 | cb(['Error occurred when sending metric request.', JSON.stringify(_payload)].join(' '), null); 79 | }); 80 | }; 81 | 82 | return metricsHelper; 83 | 84 | })(); 85 | 86 | module.exports = metricsHelper; 87 | -------------------------------------------------------------------------------- /source/resources/helper/lib/iot-helper.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let moment = require('moment'); 21 | let AWS = require('aws-sdk'); 22 | 23 | /** 24 | * Helper function to interact with AWS IoT for cfn custom resource. 25 | * 26 | * @class iotHelper 27 | */ 28 | let iotHelper = (function() { 29 | 30 | /** 31 | * @class iotHelper 32 | * @constructor 33 | */ 34 | let iotHelper = function() {}; 35 | 36 | /** 37 | * Creates an IoT topic rule. Stop gap for missing dynamoDBv2 in CFN. 38 | * @param {string} settings - Settings for creation of the IoT topic rule. 39 | * @param {createTopicRule~requestCallback} cb - The callback that handles the response. 40 | */ 41 | iotHelper.prototype.createTopicRule = function(settings, cb) { 42 | 43 | var params = { 44 | ruleName: settings.name, 45 | topicRulePayload: { 46 | actions: settings.actions, 47 | sql: settings.sql, 48 | description: settings.description, 49 | ruleDisabled: false 50 | } 51 | }; 52 | 53 | var iot = new AWS.Iot(); 54 | iot.createTopicRule(params, function(err, data) { 55 | if (err) { 56 | return cb(err, null); 57 | } 58 | 59 | return cb(null, data); 60 | 61 | }); 62 | }; 63 | 64 | /** 65 | * Deletes an IoT topic rule. Stop gap for missing dynamoDBv2 in CFN. 66 | * @param {string} settings - Settings for deletion of the IoT topic rule. 67 | * @param {deleteTopicRule~requestCallback} cb - The callback that handles the response. 68 | */ 69 | iotHelper.prototype.deleteTopicRule = function(settings, cb) { 70 | 71 | var params = { 72 | ruleName: settings.name 73 | }; 74 | 75 | var iot = new AWS.Iot(); 76 | iot.deleteTopicRule(params, function(err, data) { 77 | if (err) { 78 | console.log(err); 79 | } 80 | 81 | return cb(null, data); 82 | 83 | }); 84 | }; 85 | 86 | return iotHelper; 87 | 88 | })(); 89 | 90 | module.exports = iotHelper; 91 | -------------------------------------------------------------------------------- /source/services/driversafety/lib/driver-safety.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let DriverSafety = require('./driver-safety.js'); 10 | 11 | describe('driversafety', function() { 12 | 13 | describe('#updateVehicleTrip', function() { 14 | 15 | let payload = { 16 | vin: 'SAMPLEVIN123', 17 | trip_id: 'TRIPID123' 18 | }; 19 | 20 | beforeEach(function() {}); 21 | 22 | afterEach(function() { 23 | AWS.restore('DynamoDB.DocumentClient'); 24 | }); 25 | 26 | it('should return success when ddb update is successful', function(done) { 27 | 28 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 29 | callback(null, { 30 | result: 'success' 31 | }); 32 | }); 33 | 34 | let _driverSafety = new DriverSafety(); 35 | _driverSafety.updateVehicleTrip(payload, function(err, data) { 36 | if (err) done(err); 37 | else { 38 | assert.equal(data.result, 'success'); 39 | done(); 40 | } 41 | }); 42 | }); 43 | 44 | it('should return error information when ddb update fails', function(done) { 45 | 46 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 47 | callback('error', null); 48 | }); 49 | 50 | let _driverSafety = new DriverSafety(); 51 | _driverSafety.updateVehicleTrip(payload, function(err, data) { 52 | if (err) { 53 | expect(err).to.equal('error'); 54 | done(); 55 | } else { 56 | done('invalid failure for negative test'); 57 | } 58 | }); 59 | 60 | }); 61 | }); 62 | 63 | describe('#getDriverScorePrediction', function() { 64 | 65 | let payload = { 66 | vin: 'SAMPLEVIN123', 67 | trip_id: 'TRIPID123' 68 | }; 69 | 70 | beforeEach(function() {}); 71 | 72 | afterEach(function() { 73 | AWS.restore('DynamoDB.DocumentClient'); 74 | }); 75 | 76 | it('should return success when driver prediction and update are successful', function(done) { 77 | 78 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 79 | callback(null, { 80 | result: 'success' 81 | }); 82 | }); 83 | 84 | let _driverSafety = new DriverSafety(); 85 | _driverSafety.updateVehicleTrip(payload, function(err, data) { 86 | if (err) done(err); 87 | else { 88 | assert.equal(data.result, 'success'); 89 | done(); 90 | } 91 | }); 92 | }); 93 | 94 | it('should return error information when driver prediction or update fails', function(done) { 95 | 96 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 97 | callback('error', null); 98 | }); 99 | 100 | let _driverSafety = new DriverSafety(); 101 | _driverSafety.updateVehicleTrip(payload, function(err, data) { 102 | if (err) { 103 | expect(err).to.equal('error'); 104 | done(); 105 | } else { 106 | done('invalid failure for negative test'); 107 | } 108 | }); 109 | 110 | }); 111 | }); 112 | 113 | }); 114 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/vehicle.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let Vehicle = require('./vehicle.js'); 10 | 11 | describe('vehicle', function() { 12 | 13 | describe('#listVehicles', function() { 14 | 15 | let _test_vehicle = { 16 | owner: 'user_test_com', 17 | vin: 'SAMPLEVIN123', 18 | nickname: 'Test Vehicle', 19 | odometer: 123 20 | }; 21 | 22 | let _ticket = { 23 | 'cognito:username': 'user_test_com' 24 | }; 25 | 26 | beforeEach(function() {}); 27 | 28 | afterEach(function() { 29 | AWS.restore('DynamoDB.DocumentClient'); 30 | }); 31 | 32 | it('should return list of vehicles when ddb query is successful', function(done) { 33 | 34 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 35 | callback(null, { 36 | Items: [_test_vehicle] 37 | }); 38 | }); 39 | 40 | let _vehicle = new Vehicle(); 41 | _vehicle.listVehicles(_ticket, function(err, data) { 42 | if (err) done(err); 43 | else { 44 | assert.equal(data.Items.length, 1); 45 | done(); 46 | } 47 | }); 48 | }); 49 | 50 | it('should return error information when ddb query fails', function(done) { 51 | 52 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 53 | callback('error', null); 54 | }); 55 | 56 | let _vehicle = new Vehicle(); 57 | _vehicle.listVehicles(_ticket, function(err, data) { 58 | if (err) { 59 | expect(err).to.equal('error'); 60 | done(); 61 | } else { 62 | done('invalid failure for negative test'); 63 | } 64 | }); 65 | 66 | }); 67 | }); 68 | 69 | describe('#getVehicle', function() { 70 | 71 | let _test_vehicle = { 72 | owner: 'user_test_com', 73 | vin: 'SAMPLEVIN123', 74 | nickname: 'Test Vehicle', 75 | odometer: 123 76 | }; 77 | 78 | let _ticket = { 79 | 'cognito:username': 'user_test_com' 80 | }; 81 | 82 | beforeEach(function() {}); 83 | 84 | afterEach(function() { 85 | AWS.restore('DynamoDB.DocumentClient'); 86 | }); 87 | 88 | it('should return a vehicle when ddb get is successful', function(done) { 89 | 90 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 91 | callback(null, { 92 | Item: _test_vehicle 93 | }); 94 | }); 95 | 96 | let _vehicle = new Vehicle(); 97 | _vehicle.getVehicle(_ticket, _test_vehicle.vin, function(err, data) { 98 | if (err) done(err); 99 | else { 100 | assert.equal(data, _test_vehicle); 101 | done(); 102 | } 103 | }); 104 | }); 105 | 106 | it('should return error information when ddb get fails', function(done) { 107 | 108 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 109 | callback('error', null); 110 | }); 111 | 112 | let _vehicle = new Vehicle(); 113 | _vehicle.getVehicle(_ticket, _test_vehicle.vin, function(err, data) { 114 | if (err) { 115 | expect(err).to.equal('error'); 116 | done(); 117 | } else { 118 | done('invalid failure for negative test'); 119 | } 120 | }); 121 | 122 | }); 123 | }); 124 | 125 | }); 126 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/vehicle.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.VEHICLE_OWNER_TBL; 31 | 32 | /** 33 | * Performs operations for vehicle management actions interfacing primiarly with 34 | * Amazon DynamoDB table. 35 | * 36 | * @class vehicle 37 | */ 38 | let vehicle = (function() { 39 | 40 | /** 41 | * @class vehicle 42 | * @constructor 43 | */ 44 | let vehicle = function() {}; 45 | 46 | /** 47 | * Retrieves a user's vehicles. 48 | * @param {JSON} ticket - authentication ticket 49 | * @param {listVehicles~callback} cb - The callback that handles the response. 50 | */ 51 | vehicle.prototype.listVehicles = function(ticket, cb) { 52 | var params = { 53 | TableName: ddbTable, 54 | KeyConditionExpression: 'owner_id = :uid', 55 | ExpressionAttributeValues: { 56 | ':uid': ticket['cognito:username'] 57 | } 58 | }; 59 | 60 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 61 | docClient.query(params, function(err, data) { 62 | if (err) { 63 | console.log(err); 64 | return cb(err, null); 65 | } 66 | 67 | return cb(null, data); 68 | }); 69 | 70 | }; 71 | 72 | /** 73 | * Registers a vehicle to and owner. 74 | * @param {JSON} ticket - authentication ticket 75 | * @param {JSON} vehicle - vehicle object 76 | * @param {createVehicle~callback} cb - The callback that handles the response. 77 | */ 78 | vehicle.prototype.createVehicle = function(ticket, vehicle, cb) { 79 | 80 | vehicle.owner_id = ticket['cognito:username']; 81 | 82 | let params = { 83 | TableName: ddbTable, 84 | Item: vehicle 85 | }; 86 | 87 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 88 | docClient.put(params, function(err, data) { 89 | if (err) { 90 | console.log(err); 91 | return cb(err, null); 92 | } 93 | 94 | return cb(null, vehicle); 95 | }); 96 | 97 | }; 98 | 99 | /** 100 | * Retrieves a user's registered vehicle. 101 | * @param {JSON} ticket - authentication ticket 102 | * @param {string} vin - vehicle identification number 103 | * @param {getVehicle~callback} cb - The callback that handles the response. 104 | */ 105 | vehicle.prototype.getVehicle = function(ticket, vin, cb) { 106 | 107 | let params = { 108 | TableName: ddbTable, 109 | Key: { 110 | owner_id: ticket['cognito:username'], 111 | vin: vin 112 | } 113 | }; 114 | 115 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 116 | docClient.get(params, function(err, data) { 117 | if (err) { 118 | console.log(err); 119 | return cb(err, null); 120 | } 121 | 122 | if (!_.isEmpty(data)) { 123 | return cb(null, data.Item); 124 | } else { 125 | return cb({ 126 | error: { 127 | message: 'The vehicle requested does not exist.' 128 | } 129 | }, null); 130 | } 131 | }); 132 | 133 | }; 134 | 135 | return vehicle; 136 | 137 | })(); 138 | 139 | module.exports = vehicle; 140 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/anomaly.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let Anomaly = require('./anomaly.js'); 10 | 11 | describe('anomaly', function() { 12 | 13 | describe('#listDtcByVehicle', function() { 14 | 15 | let _test_vehicle = { 16 | owner: 'user_test_com', 17 | vin: 'SAMPLEVIN123', 18 | nickname: 'Test Vehicle', 19 | odometer: 123 20 | }; 21 | 22 | let _test_anomaly = { 23 | acknowledged: false, 24 | anomaly_id: 'TEST123', 25 | vin: 'SAMPLEVIN123' 26 | }; 27 | 28 | let _ticket = { 29 | 'cognito:username': 'user_test_com' 30 | }; 31 | 32 | beforeEach(function() {}); 33 | 34 | afterEach(function() { 35 | AWS.restore('DynamoDB.DocumentClient'); 36 | }); 37 | 38 | it('should return list of dtc records when ddb query is successful', function(done) { 39 | 40 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 41 | callback(null, { 42 | Item: _test_vehicle 43 | }); 44 | }); 45 | 46 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 47 | callback(null, { 48 | Items: [_test_anomaly] 49 | }); 50 | }); 51 | 52 | let _anomaly = new Anomaly(); 53 | _anomaly.listAnomaliesByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 54 | if (err) done(err); 55 | else { 56 | assert.equal(data.Items.length, 1); 57 | done(); 58 | } 59 | }); 60 | }); 61 | 62 | it('should return error information when ddb query fails', function(done) { 63 | 64 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 65 | callback(null, { 66 | Item: _test_vehicle 67 | }); 68 | }); 69 | 70 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 71 | callback('error', null); 72 | }); 73 | 74 | let _anomaly = new Anomaly(); 75 | _anomaly.listAnomaliesByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 76 | if (err) { 77 | expect(err).to.equal('error'); 78 | done(); 79 | } else { 80 | done('invalid failure for negative test'); 81 | } 82 | }); 83 | 84 | }); 85 | }); 86 | 87 | describe('#getVehicleAnomaly', function() { 88 | 89 | let _test_vehicle = { 90 | owner: 'user_test_com', 91 | vin: 'SAMPLEVIN123', 92 | nickname: 'Test Vehicle', 93 | odometer: 123 94 | }; 95 | 96 | let _test_anomaly = { 97 | acknowledged: false, 98 | anomaly_id: 'TEST123', 99 | vin: 'SAMPLEVIN123' 100 | }; 101 | 102 | let _ticket = { 103 | 'cognito:username': 'user_test_com' 104 | }; 105 | 106 | beforeEach(function() {}); 107 | 108 | afterEach(function() { 109 | AWS.restore('DynamoDB.DocumentClient'); 110 | }); 111 | 112 | it('should return a anomaly when ddb get is successful', function(done) { 113 | 114 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 115 | if (params.TableName === 'tblowner') { 116 | callback(null, { 117 | Item: _test_vehicle 118 | }); 119 | } else { 120 | callback(null, { 121 | Item: _test_anomaly 122 | }); 123 | } 124 | }); 125 | 126 | let _anomaly = new Anomaly(); 127 | _anomaly.getVehicleAnomaly(_ticket, _test_vehicle.vin, _test_anomaly.anomaly_id, 128 | function(err, data) { 129 | if (err) done(err); 130 | else { 131 | assert.equal(data, _test_anomaly); 132 | done(); 133 | } 134 | }); 135 | }); 136 | 137 | it('should return error information when ddb get fails', function(done) { 138 | 139 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 140 | if (params.TableName === 'tblowner') { 141 | callback(null, { 142 | Item: _test_vehicle 143 | }); 144 | } else { 145 | callback('error', null); 146 | } 147 | }); 148 | 149 | let _anomaly = new Anomaly(); 150 | _anomaly.getVehicleAnomaly(_ticket, _test_vehicle.vin, _test_anomaly.anomaly_id, 151 | function(err, data) { 152 | 153 | if (err) { 154 | expect(err).to.equal('error'); 155 | done(); 156 | } else { 157 | done('invalid failure for negative test'); 158 | } 159 | }); 160 | }); 161 | }); 162 | 163 | }); 164 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/healthreport.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let HealthReport = require('./healthreport.js'); 10 | 11 | describe('healthreport', function() { 12 | 13 | describe('#listHealthReportsByVehicle', function() { 14 | 15 | let _test_vehicle = { 16 | owner: 'user_test_com', 17 | vin: 'SAMPLEVIN123', 18 | nickname: 'Test Vehicle', 19 | odometer: 123 20 | }; 21 | 22 | let _test_report = { 23 | report_id: '07dd5551-9e27-4fd5-813d-f5e009d773d0', 24 | vin: 'SAMPLEVIN123', 25 | owner_id: 'user_test_com' 26 | }; 27 | 28 | let _ticket = { 29 | 'cognito:username': 'user_test_com' 30 | }; 31 | 32 | beforeEach(function() {}); 33 | 34 | afterEach(function() { 35 | AWS.restore('DynamoDB.DocumentClient'); 36 | }); 37 | 38 | it('should return list of health report records when ddb query is successful', function(done) { 39 | 40 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 41 | callback(null, { 42 | Item: _test_vehicle 43 | }); 44 | }); 45 | 46 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 47 | callback(null, { 48 | Items: [_test_report] 49 | }); 50 | }); 51 | 52 | let _hr = new HealthReport(); 53 | _hr.listHealthReportsByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 54 | if (err) done(err); 55 | else { 56 | assert.equal(data.Items.length, 1); 57 | done(); 58 | } 59 | }); 60 | }); 61 | 62 | it('should return error information when ddb query fails', function(done) { 63 | 64 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 65 | callback(null, { 66 | Item: _test_vehicle 67 | }); 68 | }); 69 | 70 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 71 | callback('error', null); 72 | }); 73 | 74 | let _hr = new HealthReport(); 75 | _hr.listHealthReportsByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 76 | if (err) { 77 | expect(err).to.equal('error'); 78 | done(); 79 | } else { 80 | done('invalid failure for negative test'); 81 | } 82 | }); 83 | 84 | }); 85 | }); 86 | 87 | describe('#getVehicleHealthReport', function() { 88 | 89 | let _test_vehicle = { 90 | owner: 'user_test_com', 91 | vin: 'SAMPLEVIN123', 92 | nickname: 'Test Vehicle', 93 | odometer: 123 94 | }; 95 | 96 | let _test_report = { 97 | report_id: '07dd5551-9e27-4fd5-813d-f5e009d773d0', 98 | vin: 'SAMPLEVIN123', 99 | owner_id: 'user_test_com' 100 | }; 101 | 102 | let _ticket = { 103 | 'cognito:username': 'user_test_com' 104 | }; 105 | 106 | beforeEach(function() {}); 107 | 108 | afterEach(function() { 109 | AWS.restore('DynamoDB.DocumentClient'); 110 | }); 111 | 112 | it('should return a health report when ddb get is successful', function(done) { 113 | 114 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 115 | if (params.TableName === 'tblowner') { 116 | callback(null, { 117 | Item: _test_vehicle 118 | }); 119 | } else { 120 | callback(null, { 121 | Item: _test_report 122 | }); 123 | } 124 | }); 125 | 126 | let _hr = new HealthReport(); 127 | _hr.getVehicleHealthReport(_ticket, _test_vehicle.vin, _test_report.report_id, 128 | function(err, data) { 129 | if (err) done(err); 130 | else { 131 | assert.equal(data, _test_report); 132 | done(); 133 | } 134 | }); 135 | }); 136 | 137 | it('should return error information when ddb get fails', function(done) { 138 | 139 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 140 | if (params.TableName === 'tblowner') { 141 | callback(null, { 142 | Item: _test_vehicle 143 | }); 144 | } else { 145 | callback('error', null); 146 | } 147 | }); 148 | 149 | let _hr = new HealthReport(); 150 | _hr.getVehicleHealthReport(_ticket, _test_vehicle.vin, _test_report.report_id, 151 | function(err, data) { 152 | if (err) { 153 | expect(err).to.equal('error'); 154 | done(); 155 | } else { 156 | done('invalid failure for negative test'); 157 | } 158 | }); 159 | }); 160 | }); 161 | 162 | }); 163 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/trip.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let Trip = require('./trip.js'); 10 | 11 | describe('vehicle', function() { 12 | 13 | describe('#listDtcByVehicle', function() { 14 | 15 | let _test_vehicle = { 16 | owner: 'user_test_com', 17 | vin: 'SAMPLEVIN123', 18 | nickname: 'Test Vehicle', 19 | odometer: 123 20 | }; 21 | 22 | let _test_trip = { 23 | trip_id: '07dd5551-9e27-4fd5-813d-f5e009d773d0', 24 | vin: 'SAMPLEVIN123' 25 | }; 26 | 27 | let _ticket = { 28 | 'cognito:username': 'user_test_com' 29 | }; 30 | 31 | beforeEach(function() {}); 32 | 33 | afterEach(function() { 34 | AWS.restore('DynamoDB.DocumentClient'); 35 | }); 36 | 37 | it('should return list of trip records when ddb query is successful', function(done) { 38 | 39 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 40 | callback(null, { 41 | Item: _test_vehicle 42 | }); 43 | }); 44 | 45 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 46 | callback(null, { 47 | Items: [_test_trip] 48 | }); 49 | }); 50 | 51 | let _trip = new Trip(); 52 | _trip.listTripsByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 53 | if (err) done(err); 54 | else { 55 | assert.equal(data.Items.length, 1); 56 | done(); 57 | } 58 | }); 59 | }); 60 | 61 | it('should return error information when ddb query fails', function(done) { 62 | 63 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 64 | callback(null, { 65 | Item: _test_vehicle 66 | }); 67 | }); 68 | 69 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 70 | callback('error', null); 71 | }); 72 | 73 | let _trip = new Trip(); 74 | _trip.listTripsByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 75 | if (err) { 76 | expect(err).to.equal('error'); 77 | done(); 78 | } else { 79 | done('invalid failure for negative test'); 80 | } 81 | }); 82 | 83 | }); 84 | }); 85 | 86 | // describe('#getVehicleDtc', function() { 87 | // 88 | // let _test_vehicle = { 89 | // owner: 'user_test_com', 90 | // vin: 'SAMPLEVIN123', 91 | // nickname: 'Test Vehicle', 92 | // odometer: 123 93 | // }; 94 | // 95 | // let _test_dtc = { 96 | // acknowledged: false, 97 | // created_at: '2017-04-27T14:49:36Z', 98 | // udpated_at: '2017-04-27T14:49:36Z', 99 | // generated: '2017-04-27T14:49:34Z', 100 | // description: 'No description available.', 101 | // description: 'No description available.', 102 | // dtc: 'P0485', 103 | // dtc_id: 'TEST123', 104 | // vin: 'SAMPLEVIN123', 105 | // steps: [] 106 | // }; 107 | // 108 | // let _ticket = { 109 | // 'cognito:username': 'user_test_com' 110 | // }; 111 | // 112 | // beforeEach(function() {}); 113 | // 114 | // afterEach(function() { 115 | // AWS.restore('DynamoDB.DocumentClient'); 116 | // }); 117 | // 118 | // it('should return a vehicle when ddb get is successful', function(done) { 119 | // 120 | // AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 121 | // callback(null, { 122 | // Item: _test_vehicle 123 | // }); 124 | // }); 125 | // 126 | // AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 127 | // callback(null, { 128 | // Item: _test_vehicle 129 | // }); 130 | // }); 131 | // 132 | // let _vehicle = new Vehicle(); 133 | // _vehicle.getVehicle(_ticket, _test_vehicle.vin, function(err, data) { 134 | // if (err) done(err); 135 | // else { 136 | // assert.equal(data, _test_vehicle); 137 | // done(); 138 | // } 139 | // }); 140 | // }); 141 | // 142 | // it('should return error information when ddb get fails', function(done) { 143 | // 144 | // AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 145 | // callback('error', null); 146 | // }); 147 | // 148 | // let _vehicle = new Vehicle(); 149 | // _vehicle.getVehicle(_ticket, _test_vehicle.vin, function(err, data) { 150 | // if (err) { 151 | // expect(err).to.equal('error'); 152 | // done(); 153 | // } else { 154 | // done('invalid failure for negative test'); 155 | // } 156 | // }); 157 | // 158 | // }); 159 | // }); 160 | 161 | }); 162 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/dtc.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let Dtc = require('./dtc.js'); 10 | 11 | describe('vehicle', function() { 12 | 13 | describe('#listDtcByVehicle', function() { 14 | 15 | let _test_vehicle = { 16 | owner: 'user_test_com', 17 | vin: 'SAMPLEVIN123', 18 | nickname: 'Test Vehicle', 19 | odometer: 123 20 | }; 21 | 22 | let _test_dtc = { 23 | acknowledged: false, 24 | created_at: '2017-04-27T14:49:36Z', 25 | udpated_at: '2017-04-27T14:49:36Z', 26 | generated: '2017-04-27T14:49:34Z', 27 | description: 'No description available.', 28 | description: 'No description available.', 29 | dtc: 'P0485', 30 | dtc_id: 'TEST123', 31 | vin: 'SAMPLEVIN123', 32 | steps: [] 33 | }; 34 | 35 | let _ticket = { 36 | 'cognito:username': 'user_test_com' 37 | }; 38 | 39 | beforeEach(function() {}); 40 | 41 | afterEach(function() { 42 | AWS.restore('DynamoDB.DocumentClient'); 43 | }); 44 | 45 | it('should return list of dtc records when ddb query is successful', function(done) { 46 | 47 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 48 | callback(null, { 49 | Item: _test_vehicle 50 | }); 51 | }); 52 | 53 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 54 | callback(null, { 55 | Items: [_test_dtc] 56 | }); 57 | }); 58 | 59 | let _dtc = new Dtc(); 60 | _dtc.listDtcByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 61 | if (err) done(err); 62 | else { 63 | assert.equal(data.Items.length, 1); 64 | done(); 65 | } 66 | }); 67 | }); 68 | 69 | it('should return error information when ddb query fails', function(done) { 70 | 71 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 72 | callback(null, { 73 | Item: _test_vehicle 74 | }); 75 | }); 76 | 77 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 78 | callback('error', null); 79 | }); 80 | 81 | let _dtc = new Dtc(); 82 | _dtc.listDtcByVehicle(_ticket, _test_vehicle.vin, function(err, data) { 83 | if (err) { 84 | expect(err).to.equal('error'); 85 | done(); 86 | } else { 87 | done('invalid failure for negative test'); 88 | } 89 | }); 90 | 91 | }); 92 | }); 93 | 94 | // describe('#getVehicleDtc', function() { 95 | // 96 | // let _test_vehicle = { 97 | // owner: 'user_test_com', 98 | // vin: 'SAMPLEVIN123', 99 | // nickname: 'Test Vehicle', 100 | // odometer: 123 101 | // }; 102 | // 103 | // let _test_dtc = { 104 | // acknowledged: false, 105 | // created_at: '2017-04-27T14:49:36Z', 106 | // udpated_at: '2017-04-27T14:49:36Z', 107 | // generated: '2017-04-27T14:49:34Z', 108 | // description: 'No description available.', 109 | // description: 'No description available.', 110 | // dtc: 'P0485', 111 | // dtc_id: 'TEST123', 112 | // vin: 'SAMPLEVIN123', 113 | // steps: [] 114 | // }; 115 | // 116 | // let _ticket = { 117 | // 'cognito:username': 'user_test_com' 118 | // }; 119 | // 120 | // beforeEach(function() {}); 121 | // 122 | // afterEach(function() { 123 | // AWS.restore('DynamoDB.DocumentClient'); 124 | // }); 125 | // 126 | // it('should return a vehicle when ddb get is successful', function(done) { 127 | // 128 | // AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 129 | // callback(null, { 130 | // Item: _test_vehicle 131 | // }); 132 | // }); 133 | // 134 | // AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 135 | // callback(null, { 136 | // Item: _test_vehicle 137 | // }); 138 | // }); 139 | // 140 | // let _vehicle = new Vehicle(); 141 | // _vehicle.getVehicle(_ticket, _test_vehicle.vin, function(err, data) { 142 | // if (err) done(err); 143 | // else { 144 | // assert.equal(data, _test_vehicle); 145 | // done(); 146 | // } 147 | // }); 148 | // }); 149 | // 150 | // it('should return error information when ddb get fails', function(done) { 151 | // 152 | // AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 153 | // callback('error', null); 154 | // }); 155 | // 156 | // let _vehicle = new Vehicle(); 157 | // _vehicle.getVehicle(_ticket, _test_vehicle.vin, function(err, data) { 158 | // if (err) { 159 | // expect(err).to.equal('error'); 160 | // done(); 161 | // } else { 162 | // done('invalid failure for negative test'); 163 | // } 164 | // }); 165 | // 166 | // }); 167 | // }); 168 | 169 | }); 170 | -------------------------------------------------------------------------------- /deployment/build-s3-dist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This assumes all of the OS-level configuration has been completed and git repo has already been cloned 4 | # 5 | # This script should be run from the repo's deployment directory 6 | # cd deployment 7 | # ./build-s3-dist.sh source-bucket-base-name trademarked-solution-name version-code 8 | # 9 | # Paramenters: 10 | # - source-bucket-base-name: Name for the S3 bucket location where the template will source the Lambda 11 | # code from. The template will append '-[region_name]' to this bucket name. 12 | # For example: ./build-s3-dist.sh solutions my-solution v1.0.0 13 | # The template will then expect the source code to be located in the solutions-[region_name] bucket 14 | # 15 | # - trademarked-solution-name: name of the solution for consistency 16 | # 17 | # - version-code: version of the package 18 | 19 | # Check to see if input has been provided: 20 | if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then 21 | echo "Please provide the base source bucket name, trademark approved solution name, version and template bucket name where the lambda code will eventually reside." 22 | echo "For example: ./build-s3-dist.sh solutions trademarked-solution-name v1.0.0" 23 | exit 1 24 | fi 25 | 26 | # Get reference for all important folders 27 | template_dir="$PWD" 28 | template_dist_dir="$template_dir/global-s3-assets" 29 | build_dist_dir="$template_dir/regional-s3-assets" 30 | source_dir="$template_dir/../source" 31 | 32 | echo "------------------------------------------------------------------------------" 33 | echo "[Init] Clean old dist folders" 34 | echo "------------------------------------------------------------------------------" 35 | echo "rm -rf $template_dist_dir" 36 | rm -rf $template_dist_dir 37 | echo "mkdir -p $template_dist_dir" 38 | mkdir -p $template_dist_dir 39 | echo "rm -rf $build_dist_dir" 40 | rm -rf $build_dist_dir 41 | echo "mkdir -p $build_dist_dir" 42 | mkdir -p $build_dist_dir 43 | 44 | echo "------------------------------------------------------------------------------" 45 | echo "[Packing] Templates" 46 | echo "------------------------------------------------------------------------------" 47 | echo "cp $template_dir/*.template $template_dist_dir" 48 | #cp -R $template_dir/*.template $template_dist_dir/ 49 | cp -R $template_dir/connected-vehicle-platform.yaml $template_dist_dir/aws-connected-vehicle-solution.template 50 | 51 | echo "Updating code source bucket in template with $1" 52 | replace="s/%%BUCKET_NAME%%/$1/g" 53 | sed -i '' -e $replace $template_dist_dir/*.template 54 | 55 | replace="s/%%SOLUTION_NAME%%/$2/g" 56 | sed -i '' -e $replace $template_dist_dir/*.template 57 | 58 | replace="s/%%VERSION%%/$3/g" 59 | sed -i '' -e $replace $template_dist_dir/*.template 60 | 61 | replace="s/%%TEMPLATE_BUCKET_NAME%%/$4/g" 62 | sed -i '' -e $replace $template_dist_dir/*.template 63 | 64 | echo "------------------------------------------------------------------------------" 65 | echo "[Rebuild] Services - anomaly" 66 | echo "------------------------------------------------------------------------------" 67 | 68 | cd $source_dir/services/anomaly 69 | npm install 70 | npm run build 71 | npm run zip 72 | cp dist/vhr-anomaly-service.zip $build_dist_dir/vhr-anomaly-service.zip 73 | 74 | echo "------------------------------------------------------------------------------" 75 | echo "[Rebuild] Services - driversafety" 76 | echo "------------------------------------------------------------------------------" 77 | 78 | cd $source_dir/services/driversafety 79 | npm install 80 | npm run build 81 | npm run zip 82 | cp dist/vhr-driver-safety-service.zip $build_dist_dir/vhr-driver-safety-service.zip 83 | 84 | echo "------------------------------------------------------------------------------" 85 | echo "[Rebuild] Services - marketing" 86 | echo "------------------------------------------------------------------------------" 87 | 88 | cd $source_dir/services/marketing 89 | npm install 90 | npm run build 91 | npm run zip 92 | cp dist/vhr-marketing-service.zip $build_dist_dir/vhr-marketing-service.zip 93 | 94 | echo "------------------------------------------------------------------------------" 95 | echo "[Rebuild] Services - dtc" 96 | echo "------------------------------------------------------------------------------" 97 | 98 | cd $source_dir/services/dtc 99 | npm install 100 | npm run build 101 | npm run zip 102 | cp dist/vhr-dtc-service.zip $build_dist_dir/vhr-dtc-service.zip 103 | 104 | echo "------------------------------------------------------------------------------" 105 | echo "[Rebuild] Services - notification" 106 | echo "------------------------------------------------------------------------------" 107 | 108 | cd $source_dir/services/notification 109 | npm install 110 | npm run build 111 | npm run zip 112 | cp dist/vhr-notification-service.zip $build_dist_dir/vhr-notification-service.zip 113 | 114 | echo "------------------------------------------------------------------------------" 115 | echo "[Rebuild] Services - vehicle" 116 | echo "------------------------------------------------------------------------------" 117 | 118 | cd $source_dir/services/vehicle 119 | npm install 120 | npm run build 121 | npm run zip 122 | cp dist/vhr-vehicle-service.zip $build_dist_dir/vhr-vehicle-service.zip 123 | 124 | echo "------------------------------------------------------------------------------" 125 | echo "[Rebuild] Services - jitr" 126 | echo "------------------------------------------------------------------------------" 127 | 128 | cd $source_dir/services/jitr 129 | npm install 130 | npm run build 131 | npm run zip 132 | cp dist/vhr-vehicle-jitr.zip $build_dist_dir/vhr-vehicle-jitr.zip 133 | 134 | echo "------------------------------------------------------------------------------" 135 | echo "[Rebuild] Resources - helper" 136 | echo "------------------------------------------------------------------------------" 137 | 138 | cd $source_dir/resources/helper 139 | npm install 140 | npm run build 141 | npm run zip 142 | cp dist/cv-deployment-helper.zip $build_dist_dir/cv-deployment-helper.zip 143 | -------------------------------------------------------------------------------- /source/services/jitr/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | /** 21 | This node.js Lambda function code creates and attaches an IoT policy to the 22 | just-in-time registered certificate. It also activates the certificate. The Lambda 23 | function is attached as a rule engine action to the registration topic 24 | Saws/events/certificates/registered/ 25 | **/ 26 | 27 | var AWS = require('aws-sdk'); 28 | 29 | exports.handler = function(event, context, callback) { 30 | 31 | //Replace it with the AWS region the lambda will be running in 32 | var region = process.env.AWS_REGION; 33 | 34 | var accountId = event.awsAccountId.toString().trim(); 35 | 36 | var iot = new AWS.Iot({ 37 | 'region': region, 38 | apiVersion: '2015-05-28' 39 | }); 40 | var certificateId = event.certificateId.toString().trim(); 41 | 42 | //Replace it with your desired topic prefix 43 | var telemetricsTopic = `connectedcar/telemetry`; 44 | var aggregationTopic = `connectedcar/trip`; 45 | var dtcTopic = `connectedcar/dtc`; 46 | var alertTopic = `connectedcar/alert`; 47 | 48 | var topicName = `connectedcar/obd`; 49 | 50 | 51 | var certificateARN = `arn:aws:iot:${region}:${accountId}:cert/${certificateId}`; 52 | var policyName = `Policy_${certificateId}`; 53 | 54 | //Policy that allows connect, publish, subscribe and receive 55 | var policy = { 56 | "Version": "2012-10-17", 57 | "Statement": [{ 58 | "Effect": "Allow", 59 | "Action": [ 60 | "iot:Connect" 61 | ], 62 | "Resource": `arn:aws:iot:${region}:${accountId}:client/` + 63 | '${iot:Certificate.Subject.CommonName}' 64 | }, { 65 | "Effect": "Allow", 66 | "Action": [ 67 | "iot:Publish", 68 | "iot:Receive" 69 | ], 70 | "Resource": [ 71 | `arn:aws:iot:${region}:${accountId}:topic/${telemetricsTopic}/` + 72 | '${iot:Certificate.Subject.Pseudonym}', 73 | `arn:aws:iot:${region}:${accountId}:topic/${aggregationTopic}/` + 74 | '${iot:Certificate.Subject.Pseudonym}', 75 | `arn:aws:iot:${region}:${accountId}:topic/${dtcTopic}/` + 76 | '${iot:Certificate.Subject.Pseudonym}', 77 | `arn:aws:iot:${region}:${accountId}:topic/${alertTopic}/` + 78 | '${iot:Certificate.Subject.Pseudonym}/*' 79 | ] 80 | }, { 81 | "Effect": "Allow", 82 | "Action": [ 83 | "iot:Subscribe", 84 | ], 85 | "Resource": [ 86 | `arn:aws:iot:${region}:${accountId}:topicfilter/${telemetricsTopic}/` + 87 | '${iot:Certificate.Subject.Pseudonym}', 88 | `arn:aws:iot:${region}:${accountId}:topicfilter/${dtcTopic}/` + 89 | '${iot:Certificate.Subject.Pseudonym}', 90 | `arn:aws:iot:${region}:${accountId}:topicfilter/${alertTopic}/` + 91 | '${iot:Certificate.Subject.Pseudonym}/*' 92 | ] 93 | }] 94 | }; 95 | 96 | /* 97 | Step 1) Create a policy 98 | */ 99 | iot.createPolicy({ 100 | policyDocument: JSON.stringify(policy), 101 | policyName: policyName 102 | }, (err, data) => { 103 | //Ignore if the policy already exists 104 | if (err && (!err.code || err.code !== 'ResourceAlreadyExistsException')) { 105 | console.log(err); 106 | callback(err, data); 107 | return; 108 | } 109 | console.log(data); 110 | 111 | /* 112 | Step 2) Attach the policy to the certificate 113 | */ 114 | iot.attachPrincipalPolicy({ 115 | policyName: policyName, 116 | principal: certificateARN 117 | }, (err, data) => { 118 | //Ignore if the policy is already attached 119 | if (err && (!err.code || err.code !== 'ResourceAlreadyExistsException')) { 120 | console.log(err); 121 | callback(err, data); 122 | return; 123 | } 124 | console.log(data); 125 | /* 126 | Step 3) Activate the certificate. Optionally, you can have your custom Certificate Revocation List (CRL) check 127 | logic here and ACTIVATE the certificate only if it is not in the CRL. Revoke the certificate if it is in the CRL 128 | */ 129 | iot.updateCertificate({ 130 | certificateId: certificateId, 131 | newStatus: 'ACTIVE' 132 | }, (err, data) => { 133 | if (err) { 134 | console.log(err, err.stack); 135 | callback(err, data); 136 | } else { 137 | console.log(data); 138 | callback(null, 139 | "Success, created, attached policy and activated the certificate " + 140 | certificateId); 141 | } 142 | }); 143 | }); 144 | }); 145 | 146 | } 147 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/trip.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.VEHICLE_TRIP_TBL; 31 | const ownerTable = process.env.VEHICLE_OWNER_TBL; 32 | 33 | /** 34 | * Performs operations for trip management actions interfacing primiarly with 35 | * Amazon DynamoDB table. 36 | * 37 | * @class trip 38 | */ 39 | let trip = (function() { 40 | 41 | /** 42 | * @class trip 43 | * @constructor 44 | */ 45 | let trip = function() {}; 46 | 47 | /** 48 | * Retrieves the trip records for a user's vehicles. 49 | * @param {JSON} ticket - authentication ticket 50 | * @param {string} vin - vehicle identification number 51 | * @param {listVehicles~callback} cb - The callback that handles the response. 52 | */ 53 | trip.prototype.listTripsByVehicle = function(ticket, vin, cb) { 54 | 55 | // verify user owns vehicle 56 | let params = { 57 | TableName: ownerTable, 58 | Key: { 59 | owner_id: ticket['cognito:username'], 60 | vin: vin 61 | } 62 | }; 63 | 64 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 65 | docClient.get(params, function(err, data) { 66 | if (err) { 67 | console.log(err); 68 | return cb(err, null); 69 | } 70 | 71 | if (!_.isEmpty(data)) { 72 | var trip_params = { 73 | TableName: ddbTable, 74 | KeyConditionExpression: 'vin = :vin', 75 | ExpressionAttributeValues: { 76 | ':vin': vin 77 | } 78 | }; 79 | 80 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 81 | docClient.query(trip_params, function(err, trip_data) { 82 | if (err) { 83 | console.log(err); 84 | return cb(err, null); 85 | } 86 | 87 | return cb(null, trip_data); 88 | }); 89 | } else { 90 | return cb({ 91 | error: { 92 | message: 'The vehicle requested is not registered under the user.' 93 | } 94 | }, null); 95 | } 96 | }); 97 | 98 | }; 99 | 100 | /** 101 | * Retrieves a specific trip record for a user's registered vehicle. 102 | * @param {JSON} ticket - authentication ticket 103 | * @param {string} vin - vehicle identification number 104 | * @param {string} tripId - Trip record id 105 | * @param {getVehicle~callback} cb - The callback that handles the response. 106 | */ 107 | trip.prototype.getVehicleTrip = function(ticket, vin, tripId, cb) { 108 | 109 | // verify user owns vehicle 110 | let params = { 111 | TableName: ownerTable, 112 | Key: { 113 | owner_id: ticket['cognito:username'], 114 | vin: vin 115 | } 116 | }; 117 | 118 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 119 | docClient.get(params, function(err, data) { 120 | if (err) { 121 | console.log(err); 122 | return cb(err, null); 123 | } 124 | 125 | if (!_.isEmpty(data)) { 126 | let trip_params = { 127 | TableName: ddbTable, 128 | Key: { 129 | vin: vin, 130 | trip_id: tripId 131 | } 132 | }; 133 | 134 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 135 | docClient.get(trip_params, function(err, trip_data) { 136 | if (err) { 137 | console.log(err); 138 | return cb(err, null); 139 | } 140 | 141 | if (!_.isEmpty(trip_data)) { 142 | return cb(null, trip_data.Item); 143 | } else { 144 | return cb({ 145 | error: { 146 | message: 'The trip record requested does not exist.' 147 | } 148 | }, null); 149 | } 150 | }); 151 | } else { 152 | return cb({ 153 | error: { 154 | message: 'The vehicle requested is not registered under the user.' 155 | } 156 | }, null); 157 | } 158 | }); 159 | 160 | }; 161 | 162 | return trip; 163 | 164 | })(); 165 | 166 | module.exports = trip; 167 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/healthreport.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.HEALTH_REPORT_TBL; 31 | const ownerTable = process.env.VEHICLE_OWNER_TBL; 32 | 33 | /** 34 | * Performs operations for health report management actions interfacing primiarly with 35 | * Amazon DynamoDB table. 36 | * 37 | * @class healthreport 38 | */ 39 | let healthreport = (function() { 40 | 41 | /** 42 | * @class healthreport 43 | * @constructor 44 | */ 45 | let healthreport = function() {}; 46 | 47 | /** 48 | * Retrieves the health report records for a user's vehicles. 49 | * @param {JSON} ticket - authentication ticket 50 | * @param {string} vin - vehicle identification number 51 | * @param {listVehicles~callback} cb - The callback that handles the response. 52 | */ 53 | healthreport.prototype.listHealthReportsByVehicle = function(ticket, vin, cb) { 54 | 55 | // verify user owns vehicle 56 | let params = { 57 | TableName: ownerTable, 58 | Key: { 59 | owner_id: ticket['cognito:username'], 60 | vin: vin 61 | } 62 | }; 63 | 64 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 65 | docClient.get(params, function(err, data) { 66 | if (err) { 67 | console.log(err); 68 | return cb(err, null); 69 | } 70 | 71 | if (!_.isEmpty(data)) { 72 | var hr_params = { 73 | TableName: ddbTable, 74 | KeyConditionExpression: 'vin = :vin', 75 | ExpressionAttributeValues: { 76 | ':vin': vin 77 | } 78 | }; 79 | 80 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 81 | docClient.query(hr_params, function(err, hr_data) { 82 | if (err) { 83 | console.log(err); 84 | return cb(err, null); 85 | } 86 | 87 | return cb(null, hr_data); 88 | }); 89 | } else { 90 | return cb({ 91 | error: { 92 | message: 'The vehicle requested is not registered under the user.' 93 | } 94 | }, null); 95 | } 96 | }); 97 | 98 | }; 99 | 100 | /** 101 | * Retrieves a specific health report record for a user's registered vehicle. 102 | * @param {JSON} ticket - authentication ticket 103 | * @param {string} vin - vehicle identification number 104 | * @param {string} reportId - Health report record id 105 | * @param {getVehicle~callback} cb - The callback that handles the response. 106 | */ 107 | healthreport.prototype.getVehicleHealthReport = function(ticket, vin, reportId, cb) { 108 | 109 | // verify user owns vehicle 110 | let params = { 111 | TableName: ownerTable, 112 | Key: { 113 | owner_id: ticket['cognito:username'], 114 | vin: vin 115 | } 116 | }; 117 | 118 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 119 | docClient.get(params, function(err, data) { 120 | if (err) { 121 | console.log(err); 122 | return cb(err, null); 123 | } 124 | 125 | if (!_.isEmpty(data)) { 126 | let hr_params = { 127 | TableName: ddbTable, 128 | Key: { 129 | vin: vin, 130 | report_id: reportId 131 | } 132 | }; 133 | 134 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 135 | docClient.get(hr_params, function(err, hr_data) { 136 | if (err) { 137 | console.log(err); 138 | return cb(err, null); 139 | } 140 | 141 | if (!_.isEmpty(hr_data)) { 142 | return cb(null, hr_data.Item); 143 | } else { 144 | return cb({ 145 | error: { 146 | message: 'The health report record requested does not exist.' 147 | } 148 | }, null); 149 | } 150 | }); 151 | } else { 152 | return cb({ 153 | error: { 154 | message: 'The vehicle requested is not registered under the user.' 155 | } 156 | }, null); 157 | } 158 | }); 159 | 160 | }; 161 | 162 | return healthreport; 163 | 164 | })(); 165 | 166 | module.exports = healthreport; 167 | -------------------------------------------------------------------------------- /source/resources/helper/lib/dynamodb-helper.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let moment = require('moment'); 21 | let AWS = require('aws-sdk'); 22 | const fs = require('fs'); 23 | let csv = require('fast-csv'); 24 | let codes_info = []; 25 | 26 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 27 | const dynamoConfig = { 28 | credentials: creds, 29 | region: process.env.AWS_REGION 30 | }; 31 | 32 | /** 33 | * Helper function to interact with dynamodb for data lake cfn custom resource. 34 | * 35 | * @class dynamoDBHelper 36 | */ 37 | let dynamoDBHelper = (function() { 38 | 39 | /** 40 | * @class dynamoDBHelper 41 | * @constructor 42 | */ 43 | let dynamoDBHelper = function() {}; 44 | 45 | /** 46 | * Loads POIs into marketing table. 47 | * @param {string} ddbTable - POI table. 48 | * @param {loadDtcCodes~requestCallback} cb - The callback that handles the response. 49 | */ 50 | dynamoDBHelper.prototype.loadPois = function(ddbTable, cb) { 51 | 52 | let parser = csv.parse(); 53 | let fileStream = fs.createReadStream('./marketing-pois.csv'); 54 | fileStream 55 | .on('readable', function() { 56 | var data; 57 | while ((data = fileStream.read()) !== null) { 58 | parser.write(data); 59 | } 60 | }) 61 | .on('end', function() { 62 | parser.end(); 63 | }); 64 | 65 | parser 66 | .on('readable', function() { 67 | var data; 68 | while ((data = parser.read()) !== null) { 69 | codes_info.push({ 70 | poi_id: data[0], 71 | address: data[1], 72 | city: data[2], 73 | latitude: data[3], 74 | longitude: data[4], 75 | message: data[5], 76 | poi: data[6], 77 | radius: data[7], 78 | state: data[8] 79 | }); 80 | } 81 | }) 82 | .on('end', function() { 83 | console.log('Attempting to load POIs to marketing table.'); 84 | loadCodes(codes_info, 0, ddbTable, function(err, data) { 85 | if (err) { 86 | console.log('Error loading POI marketing table', err); 87 | } else { 88 | console.log('Successfully loaded POI marketing table.'); 89 | } 90 | cb(null, 'success'); 91 | }); 92 | }); 93 | 94 | }; 95 | 96 | /** 97 | * Loads DTC codes into reference table. 98 | * @param {string} ddbTable - DTC reference table. 99 | * @param {loadDtcCodes~requestCallback} cb - The callback that handles the response. 100 | */ 101 | dynamoDBHelper.prototype.loadDtcCodes = function(ddbTable, cb) { 102 | 103 | let parser = csv.parse(); 104 | let fileStream = fs.createReadStream('./obd-trouble-codes.csv'); 105 | fileStream 106 | .on('readable', function() { 107 | var data; 108 | while ((data = fileStream.read()) !== null) { 109 | parser.write(data); 110 | } 111 | }) 112 | .on('end', function() { 113 | parser.end(); 114 | }); 115 | 116 | parser 117 | .on('readable', function() { 118 | var data; 119 | while ((data = parser.read()) !== null) { 120 | codes_info.push({ 121 | dtc: data[0], 122 | description: data[1], 123 | steps: [] 124 | }); 125 | } 126 | }) 127 | .on('end', function() { 128 | console.log('Attempting to load DTC codes to reference table.'); 129 | loadCodes(codes_info, 0, ddbTable, function(err, data) { 130 | if (err) { 131 | console.log('Error loading DTC reference table', err); 132 | } else { 133 | console.log('Successfully loaded DTC reference table.'); 134 | } 135 | cb(null, 'success'); 136 | }); 137 | }); 138 | 139 | }; 140 | 141 | var loadCodes = function(items, index, ddbTable, cb) { 142 | if (index < items.length) { 143 | let params = { 144 | TableName: ddbTable, 145 | Item: items[index] 146 | }; 147 | 148 | const docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 149 | docClient.put(params, function(err, data) { 150 | if (err) { 151 | console.log(err); 152 | } else { 153 | console.log(['Added DTC', params.Item.dtc].join(': ')); 154 | } 155 | 156 | index++; 157 | setTimeout(loadCodes, 500, items, index, ddbTable, cb); 158 | }); 159 | } else { 160 | return cb(null, 'All codes processed..'); 161 | } 162 | 163 | }; 164 | 165 | return dynamoDBHelper; 166 | 167 | })(); 168 | 169 | module.exports = dynamoDBHelper; 170 | -------------------------------------------------------------------------------- /source/services/notification/lib/notification.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.VEHICLE_OWNER_TBL; 31 | const poolId = process.env.USER_POOL_ID; 32 | 33 | /** 34 | * Performs operations for notification actions interfacing primiarly with 35 | * Amazon DynamoDB table, cognito and SNS. 36 | * 37 | * @class notification 38 | */ 39 | let notification = (function() { 40 | 41 | /** 42 | * @class notification 43 | * @constructor 44 | */ 45 | let notification = function() {}; 46 | 47 | /** 48 | * Send message to mobile device via SNS. 49 | * @param {payload} payload - message data payload 50 | * @param {sendNotification~callback} cb - The callback that handles the response. 51 | */ 52 | notification.prototype.sendNotification = function(payload, cb) { 53 | 54 | getVehicleOwner(payload.vin, function(err, data) { 55 | if (err) { 56 | console.log(err); 57 | return cb(err, null); 58 | } 59 | 60 | if (data.Items.length > 0) { 61 | getUser(data.Items[0].owner_id, function(err, user) { 62 | if (err) { 63 | console.log(err); 64 | return cb(err, null); 65 | } 66 | 67 | let params = { 68 | Message: payload.message.mobile, 69 | PhoneNumber: user.phone 70 | }; 71 | 72 | let sns = new AWS.SNS(); 73 | sns.publish(params, function(err, msg_data) { 74 | if (err) { 75 | console.log(err); 76 | return cb(err, null); 77 | } 78 | 79 | console.log(msg_data); 80 | return cb(null, { 81 | result: 'Owner notification sent' 82 | }); 83 | }); 84 | }); 85 | } else { 86 | return cb(null, { 87 | error: { 88 | message: 'VIN does not have an associated onwer.' 89 | } 90 | }); 91 | } 92 | }); 93 | 94 | }; 95 | 96 | /** 97 | * Send notification message via MQTT. 98 | * @param {payload} payload - message data payload 99 | * @param {sendNotiviationViaMqtt~callback} cb - The callback that handles the response. 100 | */ 101 | notification.prototype.sendNotiviationViaMqtt = function(payload, cb) { 102 | let _topic = ['connectedcar/alert', payload.vin, payload.type].join('/') 103 | 104 | var params = { 105 | topic: _topic, 106 | payload: JSON.stringify({ 107 | timestamp: moment.utc().format('YYYY-MM-DD HH:mm:ss.SSSSSSSSS'), 108 | type: payload.message.type, 109 | message: payload.message.mqtt 110 | }), 111 | qos: 0 112 | }; 113 | 114 | var iot = new AWS.Iot(); 115 | 116 | iot.describeEndpoint({}, (err, data) => { 117 | if (err) { 118 | console.log(err); 119 | return cb(err, null); 120 | } 121 | 122 | var iotdata = new AWS.IotData({ 123 | endpoint: data.endpointAddress 124 | }); 125 | 126 | iotdata.publish(params, function(err, msg_data) { 127 | if (err) { 128 | console.log(err); 129 | return cb(err, null); 130 | } 131 | 132 | return cb(null, { 133 | result: 'Owner notification sent' 134 | }); 135 | }); 136 | }); 137 | }; 138 | 139 | /** 140 | * Get the owner id for a vehicle. 141 | * @param {string} vin - vehicle identification number 142 | * @param {getVehicleOwner~callback} cb - The callback that handles the response. 143 | */ 144 | let getVehicleOwner = function(vin, cb) { 145 | 146 | var params = { 147 | TableName: ddbTable, 148 | IndexName: 'vin-index', 149 | KeyConditionExpression: 'vin = :vin', 150 | ExpressionAttributeValues: { 151 | ':vin': vin 152 | } 153 | }; 154 | 155 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 156 | docClient.query(params, function(err, data) { 157 | if (err) { 158 | console.log(err); 159 | return cb(err, null); 160 | } 161 | 162 | return cb(null, data); 163 | }); 164 | 165 | }; 166 | 167 | /** 168 | * Retrieves a user account from the Amazon Cognito user pool. 169 | * @param {integer} userId - Username of account to retrieve from the user pool. 170 | * @param {getUser~requestCallback} cb - The callback that handles the response. 171 | */ 172 | let getUser = function(userId, cb) { 173 | 174 | let params = { 175 | UserPoolId: poolId, 176 | Username: userId 177 | }; 178 | 179 | let cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider(); 180 | cognitoidentityserviceprovider.adminGetUser(params, function(err, data) { 181 | if (err) { 182 | console.log(err); 183 | return cb(err.message, null); 184 | } 185 | 186 | let _user = { 187 | user_id: data.Username, 188 | phone: '', 189 | email: '', 190 | enabled: data.Enabled, 191 | created_at: data.UserCreateDate, 192 | updated_at: data.UserLastModifiedDate 193 | }; 194 | 195 | let _em = _.where(data.UserAttributes, { 196 | Name: 'email' 197 | }); 198 | if (_em.length > 0) { 199 | _user.email = _em[0].Value; 200 | } 201 | 202 | let _phone = _.where(data.UserAttributes, { 203 | Name: 'phone_number' 204 | }); 205 | if (_phone.length > 0) { 206 | _user.phone = _phone[0].Value; 207 | } 208 | 209 | return cb(null, _user); 210 | 211 | }); 212 | 213 | }; 214 | 215 | return notification; 216 | 217 | })(); 218 | 219 | module.exports = notification; 220 | -------------------------------------------------------------------------------- /source/services/notification/lib/notification.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | let path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let Notification = require('./notification.js'); 10 | 11 | describe('notification', function() { 12 | 13 | describe('#sendNotification', function() { 14 | 15 | let payload = { 16 | vin: 'SAMPLEVIN123', 17 | message: { 18 | type: 'test', 19 | mobile: 'mobile test message', 20 | mqtt: 'mqtt test message' 21 | } 22 | }; 23 | 24 | let _test_vehicle = { 25 | owner_id: 'user_test_com', 26 | vin: 'SAMPLEVIN123', 27 | nickname: 'Test Vehicle', 28 | odometer: 123 29 | }; 30 | 31 | let _user = { 32 | Username: 'Test User', 33 | Enabled: true, 34 | UserCreateDate: '2017-03-11T14:55:22Z', 35 | UserLastModifiedDate: '2017-03-11T14:55:22Z', 36 | UserAttributes: [{ 37 | Name: 'email', 38 | Value: 'user@test.com' 39 | }, { 40 | Name: 'phone_number', 41 | Value: '111-111-1111' 42 | }] 43 | }; 44 | 45 | beforeEach(function() {}); 46 | 47 | afterEach(function() { 48 | AWS.restore('DynamoDB.DocumentClient'); 49 | AWS.restore('CognitoIdentityServiceProvider'); 50 | AWS.restore('SNS'); 51 | }); 52 | 53 | it('should return success when notification is successful sent', function(done) { 54 | 55 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 56 | callback(null, { 57 | Items: [_test_vehicle] 58 | }); 59 | }); 60 | 61 | AWS.mock('CognitoIdentityServiceProvider', 'adminGetUser', function(params, callback) { 62 | callback(null, _user); 63 | }); 64 | 65 | AWS.mock('SNS', 'publish', function(params, callback) { 66 | callback(null, { 67 | result: 'success' 68 | }); 69 | }); 70 | 71 | let _notification = new Notification(); 72 | _notification.sendNotification(payload, function(err, data) { 73 | if (err) done(err); 74 | else { 75 | assert.equal(data.result, 'Owner notification sent'); 76 | done(); 77 | } 78 | }); 79 | }); 80 | 81 | it('should return error information when ddb query fails', function(done) { 82 | 83 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 84 | callback('ddb error', null); 85 | }); 86 | 87 | AWS.mock('CognitoIdentityServiceProvider', 'adminGetUser', function(params, callback) { 88 | callback(null, _user); 89 | }); 90 | 91 | AWS.mock('SNS', 'publish', function(params, callback) { 92 | callback(null, { 93 | result: 'success' 94 | }); 95 | }); 96 | 97 | let _notification = new Notification(); 98 | _notification.sendNotification(payload, function(err, data) { 99 | if (err) { 100 | expect(err).to.equal('ddb error'); 101 | done(); 102 | } else { 103 | done('invalid failure for negative test'); 104 | } 105 | }); 106 | 107 | }); 108 | 109 | it('should return error information when cognito lookup fails', function(done) { 110 | 111 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 112 | callback(null, { 113 | Items: [_test_vehicle] 114 | }); 115 | }); 116 | 117 | AWS.mock('CognitoIdentityServiceProvider', 'adminGetUser', function(params, callback) { 118 | callback({ 119 | message: 'cognito error' 120 | }, null); 121 | }); 122 | 123 | AWS.mock('SNS', 'publish', function(params, callback) { 124 | callback(null, { 125 | result: 'success' 126 | }); 127 | }); 128 | 129 | let _notification = new Notification(); 130 | _notification.sendNotification(payload, function(err, data) { 131 | if (err) { 132 | expect(err).to.equal('cognito error'); 133 | done(); 134 | } else { 135 | done('invalid failure for negative test'); 136 | } 137 | }); 138 | 139 | }); 140 | 141 | it('should return error information when sns send fails', function(done) { 142 | 143 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 144 | callback(null, { 145 | Items: [_test_vehicle] 146 | }); 147 | }); 148 | 149 | AWS.mock('CognitoIdentityServiceProvider', 'adminGetUser', function(params, callback) { 150 | callback(null, _user); 151 | }); 152 | 153 | AWS.mock('SNS', 'publish', function(params, callback) { 154 | callback('sns error', null); 155 | }); 156 | 157 | let _notification = new Notification(); 158 | _notification.sendNotification(payload, function(err, data) { 159 | if (err) { 160 | expect(err).to.equal('sns error'); 161 | done(); 162 | } else { 163 | done('invalid failure for negative test'); 164 | } 165 | }); 166 | 167 | }); 168 | 169 | }); 170 | 171 | describe('#sendNotiviationViaMqtt', function() { 172 | 173 | let payload = { 174 | vin: 'SAMPLEVIN123', 175 | message: { 176 | type: 'test', 177 | mobile: 'mobile test message', 178 | mqtt: 'mqtt test message' 179 | } 180 | }; 181 | 182 | beforeEach(function() {}); 183 | 184 | afterEach(function() { 185 | AWS.restore('Iot'); 186 | AWS.restore('IotData'); 187 | }); 188 | 189 | it('should return success when notification is successful sent', function(done) { 190 | 191 | AWS.mock('Iot', 'describeEndpoint', function(params, callback) { 192 | callback(null, { 193 | endpointAddress: 'sample.iot.region.amazonaws.com' 194 | }); 195 | }); 196 | 197 | AWS.mock('IotData', 'publish', function(params, callback) { 198 | callback(null, { 199 | result: 'success' 200 | }); 201 | }); 202 | 203 | let _notification = new Notification(); 204 | _notification.sendNotiviationViaMqtt(payload, function(err, data) { 205 | if (err) done(err); 206 | else { 207 | assert.equal(data.result, 'Owner notification sent'); 208 | done(); 209 | } 210 | }); 211 | }); 212 | 213 | it('should return error information when publish fails', function(done) { 214 | 215 | AWS.mock('Iot', 'describeEndpoint', function(params, callback) { 216 | callback(null, { 217 | endpointAddress: 'sample.iot.region.amazonaws.com' 218 | }); 219 | }); 220 | 221 | AWS.mock('IotData', 'publish', function(params, callback) { 222 | callback({ 223 | message: 'iotdata error' 224 | }, null); 225 | }); 226 | 227 | let _notification = new Notification(); 228 | _notification.sendNotiviationViaMqtt(payload, function(err, 229 | data) { 230 | if (err) { 231 | expect(err.message).to.equal('iotdata error'); 232 | done(); 233 | } else { 234 | done('invalid failure for negative test'); 235 | } 236 | }); 237 | 238 | }); 239 | 240 | }); 241 | 242 | }); 243 | -------------------------------------------------------------------------------- /source/services/driversafety/lib/driver-safety.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.VEHICLE_TRIP_TBL; 31 | 32 | /** 33 | * Performs operations for driver safety recording and management actions interfacing primiarly with 34 | * Amazon DynamoDB table. 35 | * 36 | * @class dtc 37 | */ 38 | let driversafety = (function() { 39 | 40 | /** 41 | * @class driversafety 42 | * @constructor 43 | */ 44 | let driversafety = function() {}; 45 | 46 | /** 47 | * Update the vehicle trip table with the driver safety score. 48 | * @param {payload} payload - trip aggregation data payload 49 | * @param {updateVehicleTrip~callback} cb - The callback that handles the response. 50 | */ 51 | driversafety.prototype.updateVehicleTrip = function(payload, cb) { 52 | 53 | let params = { 54 | TableName: ddbTable, 55 | Item: payload 56 | }; 57 | 58 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 59 | docClient.put(params, function(err, data) { 60 | if (err) { 61 | console.log(err); 62 | return cb(err, null); 63 | } 64 | 65 | return cb(null, { 66 | result: 'success' 67 | }); 68 | }); 69 | 70 | }; 71 | 72 | /** 73 | * Retrieve the driver safety score categorization predication. 74 | * @param {payload} payload - trip aggregation data payload 75 | * @param {getDriverScorePrediction~callback} cb - The callback that handles the response. 76 | */ 77 | driversafety.prototype.getDriverScorePrediction = function(payload, cb) { 78 | 79 | let _this = this; 80 | 81 | let _triptime = moment(payload.end_time).diff(moment(payload.start_time)); 82 | let _timedelta = (_triptime - payload.idle_duration) / _triptime; 83 | let _odometer = Math.ceil(payload.odometer); 84 | 85 | // payload.driver_safety_score = ((_timedelta + 86 | // ((_odometer - payload.high_braking_event) / _odometer) + 87 | // ((_odometer - payload.high_acceleration_event) / _odometer) + 88 | // ((payload.high_speed_duration / _triptime) * _odometer)) / 4) * 100; 89 | //((_odometer - payload.high_speed_duration) / _odometer)) / 4) * 100; 90 | 91 | let _raw_score = (_timedelta + 92 | Math.abs(((_odometer - payload.high_braking_event) / _odometer)) + 93 | Math.abs(((_odometer - payload.high_acceleration_event) / _odometer)) + 94 | ((payload.high_speed_duration / _triptime) * _odometer)) / 4; 95 | 96 | if (_raw_score > 1) { 97 | _raw_score = _raw_score / 100; 98 | } 99 | 100 | payload.driver_safety_score = _raw_score * 100; 101 | 102 | _this.updateVehicleTrip(payload, function(err, data) { 103 | if (err) { 104 | console.log(err); 105 | return cb(err, null); 106 | } 107 | 108 | let _score = { 109 | score: Number(Math.round(payload.driver_safety_score + 'e' + 1) + 'e-' + 1), 110 | high_acceleration_events: payload.high_acceleration_event, 111 | high_braking_events: payload.high_braking_event, 112 | high_speed_duration: payload.high_speed_duration, 113 | vehicle_speed_mean: payload.vehicle_speed_mean, 114 | milage: payload.odometer 115 | }; 116 | 117 | let _mobile = [ 118 | 'Connected Car Notification. Your driver score for your last trip was ', 119 | _score.score, '.' 120 | ].join(' '); 121 | 122 | let _message = { 123 | type: 'driverscore', 124 | mobile: _mobile, 125 | mqtt: _score 126 | } 127 | 128 | sendNotification(payload.vin, _message, function(err, msg_data) { 129 | if (err) { 130 | console.log(err); 131 | return cb(err, null); 132 | } 133 | 134 | return cb(null, data); 135 | }); 136 | }); 137 | 138 | // let machinelearning = new AWS.MachineLearning(); 139 | // 140 | // var params = { 141 | // MLModelId: process.env.MODEL_ID, 142 | // PredictEndpoint: process.env.PREDICTION_ENDPOINT, 143 | // Record: { 144 | // high_acceleration_events: payload.high_acceleration_event.toString(), 145 | // high_braking_events: payload.high_braking_event.toString(), 146 | // high_speed_duration: payload.high_speed_duration.toString(), 147 | // idle_duration: payload.idle_duration.toString(), 148 | // odometer: payload.odometer.toString(), 149 | // vehicle_speed_mean: payload.vehicle_speed_mean.toString() 150 | // } 151 | // }; 152 | // machinelearning.predict(params, function(err, prediction) { 153 | // if (err) { 154 | // console.log(err); 155 | // payload.driver_safety_score = 'NA'; 156 | // } else { 157 | // payload.driver_safety_score = prediction.Prediction.predictedValue; 158 | // } 159 | // 160 | // _this.updateVehicleTrip(payload, function(err, data) { 161 | // if (err) { 162 | // console.log(err); 163 | // return cb(err, null); 164 | // } 165 | // 166 | // let _score = Number(Math.round(payload.driver_safety_score + 'e' + 1) + 'e-' + 1); 167 | // let _mobile = [ 168 | // 'Connected Car Notification. Your driver score for your last trip was ', 169 | // _score, '.' 170 | // ].join(' '); 171 | // 172 | // let _message = { 173 | // type: 'driverscore', 174 | // mobile: _mobile, 175 | // mqtt: _score 176 | // } 177 | // 178 | // sendNotification(payload.vin, _message, function(err, msg_data) { 179 | // if (err) { 180 | // console.log(err); 181 | // return cb(err, null); 182 | // } 183 | // 184 | // return cb(null, data); 185 | // }); 186 | // }); 187 | // 188 | // }); 189 | }; 190 | 191 | let sendNotification = function(vin, message, cb) { 192 | let _payload = { 193 | vin: vin, 194 | message: message 195 | }; 196 | 197 | let params = { 198 | FunctionName: process.env.NOTIFICATION_SERVICE, 199 | InvocationType: 'Event', 200 | LogType: 'None', 201 | Payload: JSON.stringify(_payload) 202 | }; 203 | let lambda = new AWS.Lambda(); 204 | lambda.invoke(params, function(err, data) { 205 | if (err) { 206 | console.log('Error occured when triggering notification service.', err); 207 | } 208 | 209 | return cb(null, 'notification transmission triggered'); 210 | }); 211 | }; 212 | 213 | return driversafety; 214 | 215 | })(); 216 | 217 | module.exports = driversafety; 218 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/dtc.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.VEHICLE_DTC_TBL; 31 | const ownerTable = process.env.VEHICLE_OWNER_TBL; 32 | 33 | /** 34 | * Performs operations for dtc management actions interfacing primiarly with 35 | * Amazon DynamoDB table. 36 | * 37 | * @class dtc 38 | */ 39 | let dtc = (function() { 40 | 41 | /** 42 | * @class dtc 43 | * @constructor 44 | */ 45 | let dtc = function() {}; 46 | 47 | /** 48 | * Retrieves the dtc records for a user's vehicles. 49 | * @param {JSON} ticket - authentication ticket 50 | * @param {string} vin - vehicle identification number 51 | * @param {listVehicles~callback} cb - The callback that handles the response. 52 | */ 53 | dtc.prototype.listDtcByVehicle = function(ticket, vin, cb) { 54 | 55 | // verify user owns vehicle 56 | let params = { 57 | TableName: ownerTable, 58 | Key: { 59 | owner_id: ticket['cognito:username'], 60 | vin: vin 61 | } 62 | }; 63 | 64 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 65 | docClient.get(params, function(err, data) { 66 | if (err) { 67 | console.log(err); 68 | return cb(err, null); 69 | } 70 | 71 | if (!_.isEmpty(data)) { 72 | var dtc_params = { 73 | TableName: ddbTable, 74 | KeyConditionExpression: 'vin = :vin', 75 | ExpressionAttributeValues: { 76 | ':vin': vin 77 | } 78 | }; 79 | 80 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 81 | docClient.query(dtc_params, function(err, dtc_data) { 82 | if (err) { 83 | console.log(err); 84 | return cb(err, null); 85 | } 86 | 87 | return cb(null, dtc_data); 88 | }); 89 | } else { 90 | return cb({ 91 | error: { 92 | message: 'The vehicle requested is not registered under the user.' 93 | } 94 | }, null); 95 | } 96 | }); 97 | 98 | }; 99 | 100 | /** 101 | * Retrieves a specific dtc record for a user's registered vehicle. 102 | * @param {JSON} ticket - authentication ticket 103 | * @param {string} vin - vehicle identification number 104 | * @param {string} dtcId - DTC record id 105 | * @param {getVehicle~callback} cb - The callback that handles the response. 106 | */ 107 | dtc.prototype.getVehicleDtc = function(ticket, vin, dtcId, cb) { 108 | 109 | // verify user owns vehicle 110 | let params = { 111 | TableName: ownerTable, 112 | Key: { 113 | owner_id: ticket['cognito:username'], 114 | vin: vin 115 | } 116 | }; 117 | 118 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 119 | docClient.get(params, function(err, data) { 120 | if (err) { 121 | console.log(err); 122 | return cb(err, null); 123 | } 124 | 125 | if (!_.isEmpty(data)) { 126 | let dtc_params = { 127 | TableName: ddbTable, 128 | Key: { 129 | vin: vin, 130 | dtc_id: dtcId 131 | } 132 | }; 133 | 134 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 135 | docClient.get(dtc_params, function(err, dtc_data) { 136 | if (err) { 137 | console.log(err); 138 | return cb(err, null); 139 | } 140 | 141 | if (!_.isEmpty(dtc_data)) { 142 | return cb(null, dtc_data.Item); 143 | } else { 144 | return cb({ 145 | error: { 146 | message: 'The dtc record requested does not exist.' 147 | } 148 | }, null); 149 | } 150 | }); 151 | } else { 152 | return cb({ 153 | error: { 154 | message: 'The vehicle requested is not registered under the user.' 155 | } 156 | }, null); 157 | } 158 | }); 159 | 160 | }; 161 | 162 | /** 163 | * Acknowledges a specific dtc record for a user's registered vehicle. 164 | * @param {JSON} ticket - authentication ticket 165 | * @param {string} vin - vehicle identification number 166 | * @param {string} dtcId - DTC record id 167 | * @param {getVehicle~callback} cb - The callback that handles the response. 168 | */ 169 | dtc.prototype.acknowledgeVehicleDtc = function(ticket, vin, dtcId, cb) { 170 | 171 | // verify user owns vehicle 172 | let params = { 173 | TableName: ownerTable, 174 | Key: { 175 | owner_id: ticket['cognito:username'], 176 | vin: vin 177 | } 178 | }; 179 | 180 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 181 | docClient.get(params, function(err, data) { 182 | if (err) { 183 | console.log(err); 184 | return cb(err, null); 185 | } 186 | 187 | if (!_.isEmpty(data)) { 188 | let dtc_params = { 189 | TableName: ddbTable, 190 | Key: { 191 | vin: vin, 192 | dtc_id: dtcId 193 | } 194 | }; 195 | 196 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 197 | docClient.get(dtc_params, function(err, dtc_data) { 198 | if (err) { 199 | console.log(err); 200 | return cb(err, null); 201 | } 202 | 203 | if (!_.isEmpty(dtc_data)) { 204 | 205 | dtc_data.Item.acknowledged = true; 206 | 207 | let updateparams = { 208 | TableName: ddbTable, 209 | Item: dtc_data.Item 210 | }; 211 | 212 | docClient.put(updateparams, function(err, data) { 213 | if (err) { 214 | console.log(err); 215 | return cb(err, null); 216 | } 217 | 218 | return cb(null, dtc_data.Item); 219 | }); 220 | } else { 221 | return cb({ 222 | error: { 223 | message: 'The dtc record requested does not exist.' 224 | } 225 | }, null); 226 | } 227 | }); 228 | } else { 229 | return cb({ 230 | error: { 231 | message: 'The vehicle requested is not registered under the user.' 232 | } 233 | }, null); 234 | } 235 | }); 236 | 237 | }; 238 | 239 | return dtc; 240 | 241 | })(); 242 | 243 | module.exports = dtc; 244 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/anomaly.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let shortid = require('shortid'); 21 | let moment = require('moment'); 22 | let _ = require('underscore'); 23 | let AWS = require('aws-sdk'); 24 | 25 | let creds = new AWS.EnvironmentCredentials('AWS'); // Lambda provided credentials 26 | const dynamoConfig = { 27 | credentials: creds, 28 | region: process.env.AWS_REGION 29 | }; 30 | const ddbTable = process.env.VEHICLE_ANOMALY_TBL; 31 | const ownerTable = process.env.VEHICLE_OWNER_TBL; 32 | 33 | /** 34 | * Performs operations for anomaly management actions interfacing primiarly with 35 | * Amazon DynamoDB table. 36 | * 37 | * @class anomaly 38 | */ 39 | let anomaly = (function() { 40 | 41 | /** 42 | * @class anomaly 43 | * @constructor 44 | */ 45 | let anomaly = function() {}; 46 | 47 | /** 48 | * Retrieves the anomaly records for a user's vehicles. 49 | * @param {JSON} ticket - authentication ticket 50 | * @param {string} vin - vehicle identification number 51 | * @param {listVehicles~callback} cb - The callback that handles the response. 52 | */ 53 | anomaly.prototype.listAnomaliesByVehicle = function(ticket, vin, cb) { 54 | 55 | // verify user owns vehicle 56 | let params = { 57 | TableName: ownerTable, 58 | Key: { 59 | owner_id: ticket['cognito:username'], 60 | vin: vin 61 | } 62 | }; 63 | 64 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 65 | docClient.get(params, function(err, data) { 66 | if (err) { 67 | console.log(err); 68 | return cb(err, null); 69 | } 70 | 71 | if (!_.isEmpty(data)) { 72 | var anomaly_params = { 73 | TableName: ddbTable, 74 | KeyConditionExpression: 'vin = :vin', 75 | ExpressionAttributeValues: { 76 | ':vin': vin 77 | } 78 | }; 79 | 80 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 81 | docClient.query(anomaly_params, function(err, anomaly_data) { 82 | if (err) { 83 | console.log(err); 84 | return cb(err, null); 85 | } 86 | 87 | return cb(null, anomaly_data); 88 | }); 89 | } else { 90 | return cb({ 91 | error: { 92 | message: 'The vehicle requested is not registered under the user.' 93 | } 94 | }, null); 95 | } 96 | }); 97 | 98 | }; 99 | 100 | /** 101 | * Retrieves a specific anomaly record for a user's registered vehicle. 102 | * @param {JSON} ticket - authentication ticket 103 | * @param {string} vin - vehicle identification number 104 | * @param {string} anomalyId - Anomaly record id 105 | * @param {getVehicle~callback} cb - The callback that handles the response. 106 | */ 107 | anomaly.prototype.getVehicleAnomaly = function(ticket, vin, anomalyId, cb) { 108 | 109 | // verify user owns vehicle 110 | let params = { 111 | TableName: ownerTable, 112 | Key: { 113 | owner_id: ticket['cognito:username'], 114 | vin: vin 115 | } 116 | }; 117 | 118 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 119 | docClient.get(params, function(err, data) { 120 | if (err) { 121 | console.log(err); 122 | return cb(err, null); 123 | } 124 | 125 | if (!_.isEmpty(data)) { 126 | let anomaly_params = { 127 | TableName: ddbTable, 128 | Key: { 129 | vin: vin, 130 | anomaly_id: anomalyId 131 | } 132 | }; 133 | 134 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 135 | docClient.get(anomaly_params, function(err, anomaly_data) { 136 | if (err) { 137 | console.log(err); 138 | return cb(err, null); 139 | } 140 | 141 | if (!_.isEmpty(anomaly_data)) { 142 | return cb(null, anomaly_data.Item); 143 | } else { 144 | return cb({ 145 | error: { 146 | message: 'The anomaly record requested does not exist.' 147 | } 148 | }, null); 149 | } 150 | }); 151 | } else { 152 | return cb({ 153 | error: { 154 | message: 'The vehicle requested is not registered under the user.' 155 | } 156 | }, null); 157 | } 158 | }); 159 | 160 | }; 161 | 162 | /** 163 | * Acknowledges a specific anomaly record for a user's registered vehicle. 164 | * @param {JSON} ticket - authentication ticket 165 | * @param {string} vin - vehicle identification number 166 | * @param {string} anomalyId - Anomaly record id 167 | * @param {getVehicle~callback} cb - The callback that handles the response. 168 | */ 169 | anomaly.prototype.acknowledgeVehicleAnomaly = function(ticket, vin, anomalyId, cb) { 170 | 171 | // verify user owns vehicle 172 | let params = { 173 | TableName: ownerTable, 174 | Key: { 175 | owner_id: ticket['cognito:username'], 176 | vin: vin 177 | } 178 | }; 179 | 180 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 181 | docClient.get(params, function(err, data) { 182 | if (err) { 183 | console.log(err); 184 | return cb(err, null); 185 | } 186 | 187 | if (!_.isEmpty(data)) { 188 | let anomaly_params = { 189 | TableName: ddbTable, 190 | Key: { 191 | vin: vin, 192 | anomaly_id: anomalyId 193 | } 194 | }; 195 | 196 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 197 | docClient.get(anomaly_params, function(err, anomaly_data) { 198 | if (err) { 199 | console.log(err); 200 | return cb(err, null); 201 | } 202 | 203 | if (!_.isEmpty(anomaly_data)) { 204 | 205 | anomaly_data.Item.acknowledged = true; 206 | 207 | let updateparams = { 208 | TableName: ddbTable, 209 | Item: anomaly_data.Item 210 | }; 211 | 212 | docClient.put(updateparams, function(err, data) { 213 | if (err) { 214 | console.log(err); 215 | return cb(err, null); 216 | } 217 | 218 | return cb(null, anomaly_data.Item); 219 | }); 220 | } else { 221 | return cb({ 222 | error: { 223 | message: 'The anomaly record requested does not exist.' 224 | } 225 | }, null); 226 | } 227 | }); 228 | } else { 229 | return cb({ 230 | error: { 231 | message: 'The vehicle requested is not registered under the user.' 232 | } 233 | }, null); 234 | } 235 | }); 236 | 237 | }; 238 | 239 | return anomaly; 240 | 241 | })(); 242 | 243 | module.exports = anomaly; 244 | -------------------------------------------------------------------------------- /source/services/marketing/lib/marketing.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | let geolib = require('geolib'); 21 | let AWS = require('aws-sdk'); 22 | let moment = require('moment'); 23 | let _ = require('underscore'); 24 | let creds = new AWS.EnvironmentCredentials('AWS'); 25 | 26 | const marketingTable = process.env.MKT_TBL; 27 | const poiTable = process.env.POI_TBL; 28 | const dynamoConfig = { 29 | credentials: creds, 30 | region: process.env.AWS_REGION 31 | }; 32 | 33 | /** 34 | * Performs operations for location-based advertisements interfacing primiarly with 35 | * Amazon DynamoDB table. 36 | * 37 | * @class advertisement 38 | */ 39 | let advertisement = (function() { 40 | 41 | /** 42 | * @class advertisement 43 | * @constructor 44 | */ 45 | let advertisement = function() {}; 46 | 47 | /** 48 | * Retrieves points of interest from POI table. 49 | * @param {JSON} payload - location message 50 | * @param {getPoints~callback} cb - The callback that handles the response. 51 | */ 52 | advertisement.prototype.getPoints = function(payload, cb) { 53 | var params = { 54 | TableName: poiTable 55 | }; 56 | 57 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 58 | docClient.scan(params, function(err, data) { 59 | if (err) { 60 | console.log(err); 61 | return cb(err, null); 62 | } 63 | if (data) { 64 | getGeolocationResults(data.Items, 0, payload, function(err, data) { 65 | if (err) { 66 | console.log(err); 67 | return cb(err, null); 68 | } else { 69 | return cb(null, 'completed geo eval'); 70 | } 71 | }); 72 | } 73 | }); 74 | }; 75 | 76 | /** 77 | * Determines if the vehicle is near a point of interest. 78 | * @param {array} items - points of interest 79 | * @param {int} index - counter 80 | * @param {JSON} record - location message 81 | * @param {getGeolocationResults~callback} cb - The callback that handles the response. 82 | */ 83 | let getGeolocationResults = function(items, index, record, cb) { 84 | console.log(items) 85 | if (index < items.length) { 86 | console.log("processing: ", items[index]); 87 | let poi_point = {latitude: items[index].latitude, longitude: items[index].longitude}; 88 | if(geolib.isPointWithinRadius(poi_point,{latitude: record.latitude, longitude: record.longitude},items[index].radius)){ 89 | console.log('point is in circle for ' + items[index].poi); 90 | processAd(record, items[index], function(err, data) { 91 | if (err) { 92 | console.log("error processing ad"); 93 | console.log(err); 94 | return cb(err, null); 95 | } else { 96 | index++; 97 | getGeolocationResults(items, index, record, cb); 98 | } 99 | }); 100 | } else { 101 | index++; 102 | getGeolocationResults(items, index, record, cb); 103 | } 104 | 105 | } else { 106 | return cb(null, "evals complete"); 107 | } 108 | }; 109 | 110 | /** 111 | * Process the nearby point of interest. 112 | * @param {JSON} record - location message 113 | * @param {JSON} poi - nearby point of interest 114 | * @param {processAd~callback} cb - The callback that handles the response. 115 | */ 116 | let processAd = function(record,poi,cb){ 117 | var params = { 118 | TableName: marketingTable, 119 | KeyConditionExpression: 'trip_id = :tripid and poi_id = :poiid', 120 | ExpressionAttributeValues: { 121 | ':tripid': record.trip_id, 122 | ':poiid': poi.poi_id 123 | } 124 | 125 | }; 126 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 127 | docClient.query(params, function(err, adata){ 128 | if (err) { 129 | console.log(err); 130 | return cb(err, null); 131 | } 132 | if(adata) { 133 | console.log(adata); 134 | let _exist = _.find(adata.Items, function(item) { 135 | return item.poi_id === poi.poi_id; 136 | }); 137 | console.log(_exist); 138 | 139 | if (!_exist){ 140 | console.log('has not yet received this ad'); 141 | let _advertisement = { 142 | vin: record.vin, 143 | trip_id: record.trip_id, 144 | created_at: moment().utc().format(), 145 | updated_at: moment().utc().format(), 146 | identified_at: moment(record.timestamp).utc().format(), 147 | poi_id: poi.poi_id, 148 | message: poi.message, 149 | action: 'none' 150 | }; 151 | 152 | let params = { 153 | TableName: marketingTable, 154 | Item: _advertisement 155 | }; 156 | 157 | let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig); 158 | docClient.put(params, function(err, data){ 159 | if (err) { 160 | console.log(err); 161 | return cb(err, null); 162 | } 163 | if (data){ 164 | 165 | console.log(data); 166 | let _adInfo = poi.message; 167 | 168 | let _mobile = [ 169 | '*Notification from', 170 | poi.poi, 171 | '-', 172 | _adInfo 173 | ].join(' '); 174 | 175 | let _hud = _adInfo; 176 | 177 | let _message = { 178 | type: 'info', 179 | mobile: _mobile, 180 | mqtt: _hud 181 | }; 182 | 183 | sendNotification(record.vin, _message, function(err, msg_data){ 184 | if (err) { 185 | console.log(err); 186 | return cb(err, null); 187 | } 188 | console.log(msg_data); 189 | return cb(null, _advertisement); 190 | }); 191 | } 192 | }); 193 | } else { 194 | console.log('already exists'); 195 | return cb(null, {}); 196 | } 197 | } else { 198 | return cb({ 199 | error: { 200 | message: 'Error occured querying anomaly table.' 201 | } 202 | }, null); 203 | } 204 | }); 205 | }; 206 | 207 | let sendNotification = function(vin, message, cb) { 208 | let _payload = { 209 | vin: vin, 210 | message: message 211 | }; 212 | 213 | let params = { 214 | FunctionName: process.env.NOTIFICATION_SERVICE, 215 | InvocationType: 'Event', 216 | LogType: 'None', 217 | Payload: JSON.stringify(_payload) 218 | }; 219 | let lambda = new AWS.Lambda(); 220 | lambda.invoke(params, function(err, data) { 221 | if (err) { 222 | console.log('Error occured when triggering access logging service.', err); 223 | } 224 | 225 | return cb(null, 'notification transmission triggered'); 226 | }); 227 | }; 228 | 229 | return advertisement; 230 | 231 | })(); 232 | 233 | module.exports = advertisement; 234 | -------------------------------------------------------------------------------- /source/services/vehicle/lib/index.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * 5 | * with the License. A copy of the License is located at * 6 | * * 7 | * http://www.apache.org/licenses/LICENSE-2.0 * 8 | * * 9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * 10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * 11 | * and limitations under the License. * 12 | *********************************************************************************************************************/ 13 | 14 | /** 15 | * @author Solution Builders 16 | */ 17 | 18 | 'use strict'; 19 | 20 | /** 21 | * Lib 22 | */ 23 | let AWS = require('aws-sdk'); 24 | 25 | // add service library modules here 26 | let Vehicle = require('./vehicle.js'); 27 | let Dtc = require('./dtc.js'); 28 | let Trip = require('./trip.js'); 29 | let Anomaly = require('./anomaly.js'); 30 | let HealthReport = require('./healthreport.js'); 31 | 32 | // service constants 33 | const servicename = 'vehicle-service'; // name of the service for logging 34 | 35 | /** 36 | * Verifies user's authorization to execute requested action. If the request is 37 | * authorized, it is processed, otherwise a 401 unathorized result is returned 38 | * @param {JSON} event - Request event. 39 | * @param {respond~requestCallback} cb - The callback that handles the response. 40 | */ 41 | module.exports.respond = function(event, cb) { 42 | 43 | processRequest(event, cb); 44 | 45 | }; 46 | 47 | /** 48 | * Routes the request to the appropriate logic based on the request resource and method. 49 | * @param {JSON} event - Request event. 50 | * @param {JSON} ticket - authorization ticket. 51 | * @param {processRequest~requestCallback} cb - The callback that handles the response. 52 | */ 53 | function processRequest(event, cb) { 54 | 55 | // set the claims ticket 56 | let _ticket = event.requestContext.authorizer.claims; 57 | 58 | // catch error if proxied API path sent to service is not processed by available logic 59 | let INVALID_PATH_ERR = { 60 | Error: ['Invalid path request ', event.resource, ', ', event.httpMethod].join('') 61 | }; 62 | 63 | // instantiate service modules 64 | let _vehicle = new Vehicle(); 65 | let _dtc = new Dtc(); 66 | let _trip = new Trip(); 67 | let _anomaly = new Anomaly(); 68 | let _healthreport = new HealthReport(); 69 | let _response = ''; 70 | 71 | let _body = {}; 72 | let _operation = ''; 73 | if (event.body) { 74 | _body = JSON.parse(event.body); 75 | } 76 | 77 | // set logic for proxied API path 78 | if (event.resource === '/vehicles' && event.httpMethod === 'GET') { 79 | _operation = 'retrieving vehicles for user'; 80 | _vehicle.listVehicles(_ticket, function(err, data) { 81 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 82 | }); 83 | } else if (event.resource === '/vehicles' && event.httpMethod === 'POST') { 84 | _operation = 'registering vehicle for owner'; // set a description of the operation for logging 85 | _vehicle.createVehicle(_ticket, _body, function(err, data) { 86 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 87 | }); 88 | } else if (event.resource === '/vehicles/{vin}' && event.httpMethod === 'GET') { 89 | _operation = 'retrieving vehicle for user'; 90 | _vehicle.getVehicle(_ticket, event.pathParameters.vin, function(err, data) { 91 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 92 | }); 93 | } else if (event.resource === '/vehicles/{vin}/dtc' && event.httpMethod === 'GET') { 94 | _operation = 'retrieving dtc records of vehicle for user'; 95 | _dtc.listDtcByVehicle(_ticket, event.pathParameters.vin, function(err, data) { 96 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 97 | }); 98 | } else if (event.resource === '/vehicles/{vin}/dtc/{dtc_id}' && event.httpMethod === 'GET') { 99 | _operation = 'retrieving dtc record of vehicle for user'; 100 | _dtc.getVehicleDtc(_ticket, event.pathParameters.vin, event.pathParameters.dtc_id, function(err, data) { 101 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 102 | }); 103 | } else if (event.resource === '/vehicles/{vin}/dtc/{dtc_id}/acknowledge' && event.httpMethod === 'PUT') { 104 | _operation = 'acknowledge dtc record of vehicle for user'; 105 | _dtc.acknowledgeVehicleDtc(_ticket, event.pathParameters.vin, event.pathParameters.dtc_id, function(err, data) { 106 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 107 | }); 108 | } else if (event.resource === '/vehicles/{vin}/anomalies' && event.httpMethod === 'GET') { 109 | _operation = 'retrieving anomaly records of vehicle for user'; 110 | _anomaly.listAnomaliesByVehicle(_ticket, event.pathParameters.vin, function(err, data) { 111 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 112 | }); 113 | } else if (event.resource === '/vehicles/{vin}/anomalies/{anomaly_id}' && event.httpMethod === 'GET') { 114 | _operation = 'retrieving anomaly record of vehicle for user'; 115 | _anomaly.getVehicleAnomaly(_ticket, event.pathParameters.vin, event.pathParameters.anomaly_id, function(err, data) { 116 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 117 | }); 118 | } else if (event.resource === '/vehicles/{vin}/anomalies/{anomaly_id}/acknowledge' && event.httpMethod === 'PUT') { 119 | _operation = 'acknowledge anomaly record of vehicle for user'; 120 | _anomaly.acknowledgeVehicleAnomaly(_ticket, event.pathParameters.vin, event.pathParameters.anomaly_id, function(err, 121 | data) { 122 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 123 | }); 124 | } else if (event.resource === '/vehicles/{vin}/trips' && event.httpMethod === 'GET') { 125 | _operation = 'retrieving trip records of vehicle for user'; 126 | _trip.listTripsByVehicle(_ticket, event.pathParameters.vin, function(err, data) { 127 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 128 | }); 129 | } else if (event.resource === '/vehicles/{vin}/trips/{trip_id}' && event.httpMethod === 'GET') { 130 | _operation = 'retrieving trip record of vehicle for user'; 131 | _trip.getVehicleTrip(_ticket, event.pathParameters.vin, event.pathParameters.trip_id, function(err, data) { 132 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 133 | }); 134 | } else if (event.resource === '/vehicles/{vin}/healthreports' && event.httpMethod === 'GET') { 135 | _operation = 'retrieving health report records of vehicle for user'; 136 | _healthreport.listHealthReportsByVehicle(_ticket, event.pathParameters.vin, function(err, data) { 137 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 138 | }); 139 | } else if (event.resource === '/vehicles/{vin}/healthreports/{report_id}' && event.httpMethod === 'GET') { 140 | _operation = 'retrieving health report record of vehicle for user'; 141 | _healthreport.getVehicleHealthReport(_ticket, event.pathParameters.vin, event.pathParameters.report_id, function(err, 142 | data) { 143 | processResponse(err, data, _operation, event.requestContext.requestId, _ticket['cognito:username'], cb); 144 | }); 145 | } else { 146 | _response = buildOutput(500, INVALID_PATH_ERR); 147 | return cb(_response, null); 148 | } 149 | 150 | }; 151 | 152 | /** 153 | * Process operation response and log the access/result. 154 | * @param {JSON} err - Error returned from operation. 155 | * @param {JSON} data - Data returned from operation. 156 | * @param {JSON} operation - Description of operation executed. 157 | * @param {string} requestId - Id of the request. 158 | * @param {string} userid - Id of user requesting operation. 159 | * @param {processResponse~callback} cb - The callback that handles the response. 160 | */ 161 | function processResponse(err, data, operation, requestId, userid, cb) { 162 | let _response = {}; 163 | 164 | if (err) { 165 | console.log(err); 166 | _response = buildOutput(500, err); 167 | return cb(_response, null); 168 | // _accessLog.logEvent(requestId, servicename, userid, operation, 'failed/error', function(err, resp) { 169 | // return cb(_response, null); 170 | // }); 171 | } else { 172 | _response = buildOutput(200, data); 173 | return cb(null, _response); 174 | // _accessLog.logEvent(requestId, servicename, userid, operation, 'success', function(err, resp) { 175 | // return cb(null, _response); 176 | // }); 177 | } 178 | }; 179 | 180 | /** 181 | * Constructs the appropriate HTTP response. 182 | * @param {integer} statusCode - HTTP status code for the response. 183 | * @param {JSON} data - Result body to return in the response. 184 | */ 185 | function buildOutput(statusCode, data) { 186 | 187 | let _response = { 188 | statusCode: statusCode, 189 | headers: { 190 | 'Access-Control-Allow-Origin': '*' 191 | }, 192 | body: JSON.stringify(data) 193 | }; 194 | 195 | return _response; 196 | }; 197 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. -------------------------------------------------------------------------------- /source/services/dtc/lib/dtc.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('chai').assert; 4 | let expect = require('chai').expect; 5 | var path = require('path'); 6 | let AWS = require('aws-sdk-mock'); 7 | AWS.setSDK(path.resolve('./node_modules/aws-sdk')); 8 | 9 | let Dtc = require('./dtc.js'); 10 | 11 | describe('DTC', function() { 12 | 13 | let dtcRecord = { 14 | dtc_id: 'testid', 15 | vin: 'TESTVINNUMBER', 16 | dtc: 'P1234', 17 | description: 'Mass or Volume Air Flow Circuit Range/Performance Problem', 18 | steps: [], 19 | generated_at: '2017-03-11T14:55:22Z', 20 | created_at: '2017-03-11T14:55:22Z', 21 | updated_at: '2017-03-11T14:55:22Z' 22 | }; 23 | 24 | let dtcLookupRecord = { 25 | dtc: 'P1234', 26 | description: 'Mass or Volume Air Flow Circuit Range/Performance Problem' 27 | }; 28 | 29 | describe('#getVehicleDtc', function() { 30 | 31 | beforeEach(function() {}); 32 | 33 | afterEach(function() { 34 | AWS.restore('DynamoDB.DocumentClient'); 35 | }); 36 | 37 | it('should return dtc records when ddb query successful', function(done) { 38 | 39 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 40 | callback(null, { 41 | Items: [dtcRecord] 42 | }); 43 | }); 44 | 45 | let _dtc = new Dtc(); 46 | _dtc.getVehicleDtc(dtcRecord.vin, 0, function(err, data) { 47 | if (err) done(err); 48 | else { 49 | assert.equal(data.Items.length, 1); 50 | done(); 51 | } 52 | }); 53 | }); 54 | 55 | it('should return error information when ddb query fails', function(done) { 56 | 57 | AWS.mock('DynamoDB.DocumentClient', 'query', function(params, callback) { 58 | callback('error', null); 59 | }); 60 | 61 | let _dtc = new Dtc(); 62 | _dtc.getVehicleDtc(dtcRecord.vin, 0, function(err, data) { 63 | if (err) { 64 | expect(err).to.equal('error'); 65 | done(); 66 | } else { 67 | done('invalid failure for negative test'); 68 | } 69 | }); 70 | 71 | }); 72 | }); 73 | 74 | describe('#createDtc', function() { 75 | 76 | afterEach(function() { 77 | AWS.restore('DynamoDB.DocumentClient'); 78 | AWS.restore('Lambda'); 79 | }); 80 | 81 | it('should return vehicle with successful create', function(done) { 82 | 83 | let record = { 84 | timestamp: '2017-03-11 14:55:22.204000000', 85 | vin: 'TESTVINNUMBER', 86 | name: 'dtc', 87 | value: 'P1234' 88 | }; 89 | 90 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 91 | callback(null, dtcRecord); 92 | }); 93 | 94 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 95 | callback(null, { 96 | Item: dtcLookupRecord 97 | }); 98 | }); 99 | 100 | AWS.mock('Lambda', 'invoke', function(params, callback) { 101 | callback(null, { 102 | result: 'success' 103 | }); 104 | }); 105 | 106 | let _dtc = new Dtc(); 107 | _dtc.createDtc(record, function(err, data) { 108 | if (err) done(err); 109 | else { 110 | expect(data.vin).to.equal(dtcRecord.vin); 111 | expect(data.description).to.equal(dtcLookupRecord.description); 112 | expect(data.dtc).to.equal(dtcRecord.dtc); 113 | done(); 114 | } 115 | }); 116 | }); 117 | 118 | it('should return error information when ddb put fails', function(done) { 119 | 120 | let record = { 121 | timestamp: '2017-03-11 14:55:22.204000000', 122 | vin: 'TESTVINNUMBER', 123 | name: 'dtc', 124 | value: 'P1234' 125 | }; 126 | 127 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 128 | callback('ddb error', null); 129 | }); 130 | 131 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 132 | callback(null, { 133 | Item: dtcLookupRecord 134 | }); 135 | }); 136 | 137 | let _dtc = new Dtc(); 138 | _dtc.createDtc(record, function(err, data) { 139 | if (err) { 140 | expect(err).to.equal('ddb error'); 141 | done(); 142 | } else { 143 | done('invalid failure for negative test'); 144 | } 145 | }); 146 | 147 | }); 148 | }); 149 | 150 | describe('#getDtc', function() { 151 | 152 | afterEach(function() { 153 | AWS.restore('DynamoDB.DocumentClient'); 154 | }); 155 | 156 | it('should return dtc record ddb get successful', function(done) { 157 | 158 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 159 | callback(null, { 160 | Item: dtcRecord 161 | }); 162 | }); 163 | 164 | let _dtc = new Dtc(); 165 | _dtc.getDtc('testid', 'TESTVINNUMBER', function(err, data) { 166 | if (err) done(err); 167 | else { 168 | expect(data.Item).to.equal(dtcRecord); 169 | done(); 170 | } 171 | }); 172 | }); 173 | 174 | it('should return error information when ddb get fails', function(done) { 175 | 176 | let error = { 177 | error: { 178 | message: 'Failed to get object from ddb.' 179 | } 180 | }; 181 | 182 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 183 | callback(error, null); 184 | }); 185 | 186 | let _dtc = new Dtc(); 187 | _dtc.getDtc('testid', 'TESTVINNUMBER', function(err, data) { 188 | expect(err).to.eql(error); 189 | done(); 190 | }); 191 | 192 | }); 193 | }); 194 | 195 | describe('#deleteDtc', function() { 196 | 197 | afterEach(function() { 198 | AWS.restore('DynamoDB.DocumentClient'); 199 | }); 200 | 201 | it('should return empty result when ddb delete successful', function(done) { 202 | 203 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 204 | callback(null, { 205 | Item: dtcRecord 206 | }); 207 | }); 208 | 209 | AWS.mock('DynamoDB.DocumentClient', 'delete', function(params, callback) { 210 | callback(null, {}); 211 | }); 212 | 213 | let _dtc = new Dtc(); 214 | _dtc.deleteDtc('testid', 'TESTVINNUMBER', function(err, data) { 215 | if (err) done(err); 216 | else { 217 | expect(data).to.be.empty; 218 | done(); 219 | } 220 | }); 221 | }); 222 | 223 | it('should return error information when ddb delete fails', function(done) { 224 | 225 | let error = { 226 | error: { 227 | message: 'Failed to delete object from ddb.' 228 | } 229 | }; 230 | 231 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 232 | callback(null, { 233 | Item: dtcRecord 234 | }); 235 | }); 236 | 237 | AWS.mock('DynamoDB.DocumentClient', 'delete', function(params, callback) { 238 | callback(error, null); 239 | }); 240 | 241 | let _dtc = new Dtc(); 242 | _dtc.deleteDtc('testid', 'TESTVINNUMBER', function(err, data) { 243 | expect(err).to.eql(error); 244 | done(); 245 | }); 246 | 247 | }); 248 | }); 249 | 250 | describe('#updateDtc', function() { 251 | 252 | afterEach(function() { 253 | AWS.restore('DynamoDB.DocumentClient'); 254 | }); 255 | 256 | it('should return updated item when update successful', function(done) { 257 | 258 | let udpatedDtcRecord = { 259 | dtc_id: 'testid', 260 | vin: 'TESTVINNUMBER', 261 | dtc: 'P1234', 262 | description: 'Mass or Volume Air Flow Circuit Range/Performance Problem', 263 | steps: [], 264 | generated_at: '2017-03-11T14:55:22Z', 265 | created_at: '2017-03-11T14:55:22Z', 266 | updated_at: '2017-03-11T14:55:22Z', 267 | acknowledged: true 268 | }; 269 | 270 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 271 | callback(null, { 272 | Item: dtcRecord 273 | }); 274 | }); 275 | 276 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 277 | callback(null, { 278 | Item: udpatedDtcRecord 279 | }); 280 | }); 281 | 282 | let _dtc = new Dtc(); 283 | _dtc.updateVehicle(udpatedDtcRecord, function(err, data) { 284 | if (err) done(err); 285 | else { 286 | expect(data.Item).to.eql(udpatedDtcRecord); 287 | expect(data.Item.acknowledged).to.eql(true); 288 | done(); 289 | } 290 | }); 291 | }); 292 | 293 | it('should return error information when ddb put fails', function(done) { 294 | 295 | let udpatedDtcRecord = { 296 | dtc_id: 'testid', 297 | vin: 'TESTVINNUMBER', 298 | dtc: 'P1234', 299 | description: 'Mass or Volume Air Flow Circuit Range/Performance Problem', 300 | steps: [], 301 | generated_at: '2017-03-11T14:55:22Z', 302 | created_at: '2017-03-11T14:55:22Z', 303 | updated_at: '2017-03-11T14:55:22Z', 304 | acknowledged: true 305 | }; 306 | 307 | let error = { 308 | error: { 309 | message: 'Failed to update object in ddb.' 310 | } 311 | }; 312 | 313 | AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) { 314 | callback(null, { 315 | Item: dtcRecord 316 | }); 317 | }); 318 | 319 | AWS.mock('DynamoDB.DocumentClient', 'put', function(params, callback) { 320 | callback(error, null); 321 | }); 322 | 323 | let _dtc = new Dtc(); 324 | _dtc.updateVehicle(udpatedDtcRecord, function(err, data) { 325 | expect(err).to.eql(error); 326 | done(); 327 | }); 328 | 329 | }); 330 | }); 331 | 332 | }); 333 | --------------------------------------------------------------------------------