├── .eslintrc ├── .gitignore ├── README.md ├── __tests__ ├── user.test.js └── user_dev.test.js ├── app.js ├── bin └── www ├── config └── config.js ├── controllers ├── auth │ ├── UserController.js │ └── token.js └── s3 │ └── S3Controller.js ├── database ├── migrations │ └── 201808121200-create-user.js ├── mocks │ └── user.js └── scripts │ ├── user-generate.sql │ └── user.sql ├── models ├── __mocks__ │ └── index.js ├── index.js └── user.js ├── package-lock.json ├── package.json ├── public └── stylesheets │ └── style.css ├── routes ├── index.js ├── s3.js ├── user.js └── yelp.js ├── tests └── sum.js └── views ├── error.pug ├── index.pug └── layout.pug /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "rules": { 4 | "semi": ["error", "always"], 5 | "quotes": ["error", "double"], 6 | "indent": ["error", 2], 7 | "no-unreachable": 1 8 | }, 9 | "env": { 10 | "browser": false, 11 | "node": true 12 | }, 13 | "globals": { 14 | "jest": true, 15 | "describe": true, 16 | "test": true, 17 | "expect": true 18 | } 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # parcel-bundler cache (https://parceljs.org/) 61 | .cache 62 | 63 | # next.js build output 64 | .next 65 | 66 | # nuxt.js build output 67 | .nuxt 68 | 69 | # vuepress build output 70 | .vuepress/dist 71 | 72 | # Serverless directories 73 | .serverless 74 | 75 | # build files 76 | build/ 77 | 78 | # config file 79 | config/config.js 80 | config/config_dev.js 81 | config/config_local.js 82 | 83 | # not uploading pics 84 | public/images/ 85 | 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **Uber Eats API - Express.js** 2 | 3 | ![Bitrise](https://app.bitrise.io/app/622442f8e92ee3f3/status.svg?token=Hzg0GmfBVIPX2_5KPYrNRQ) 4 | ![node version](https://badge.fury.io/js/node.svg) 5 | ![Follow me](https://img.shields.io/twitter/follow/sean7218.svg?style=social&label=Follow) 6 | ![Github Followers](https://img.shields.io/github/watchers/sean7218/ubereats-api.svg?style=social&label=Follow) 7 | ![Test Coverage](https://img.shields.io/badge/test%20coverage-85%25-orange.svg) 8 | 9 | # Table of Contents 10 | 1. [User](#User) 11 | 2. [Endpionts](#) 12 | 3. [CI/CD](#Continous-Integration) 13 | ------------------------------------------------------------ 14 | # User 15 | 16 | * **URL** 17 | 18 | _https://api.zxsean.com/user/register_ 19 | 20 | * **Method:** 21 | 22 | `POST` 23 | 24 | * **URL Params** 25 | 26 | **Required:** 27 | 28 | `name=[string]` , 29 | `email=[string]` , 30 | `password=[string]` , 31 | `phone=[integer]` 32 | 33 | **Optional:** 34 | 35 | `id=[integer]` 36 | 37 | * **Data Params** 38 | 39 | ```json 40 | { 41 | "name": "Sean Zhang", 42 | "email": "sean@randomemail.com", 43 | "password": "psw123", 44 | "phone": 2023334444 45 | } 46 | ``` 47 | 48 | * **Success Response:** 49 | 50 | * **Code:** 200
51 | **Content:** `{ id : 12 }` 52 | 53 | * **Error Response:** 54 | 55 | * **Code:** 401 UNAUTHORIZED
56 | **Content:** `{ error : "registration error" }` 57 | 58 | ------------------------------------------------------------ 59 | 60 | * **URL** 61 | 62 | _https://api.zxsean.com/user/:id_ 63 | 64 | * **Method:** 65 | 66 | `GET` 67 | 68 | * **URL Params** 69 | 70 | **Required:** 71 | 72 | `id=[integer]` 73 | 74 | * **Data Params** 75 | 76 | ```json 77 | { 78 | "id": 1, 79 | } 80 | ``` 81 | 82 | * **Success Response:** 83 | 84 | * **Code:** 200
85 | **Content:** `{ id : 11 }` 86 | 87 | * **Error Response:** 88 | 89 | * **Code:** 401 UNAUTHORIZED
90 | **Content:** `{ error : "can't find user" }` 91 | 92 | ------------------------------------------------------------ 93 | * **URL** 94 | 95 | _https://api.zxsean.com/user_ 96 | 97 | * **Method:** 98 | 99 | `GET` 100 | 101 | * **URL Params** 102 | 103 | `NONE` 104 | 105 | * **Success Response:** 106 | 107 | * **Code:** 200
108 | **Content:** 109 | ```json 110 | [ 111 | { 112 | "id": 1, 113 | "name": "Kevin Hart", 114 | "email": "kevin@gmail.com", 115 | "password": "$2a$10$cVR6XquMOMHlKQzay8lErui3w6/.j2ZtVm5ai5IeeY90ZeYGXGGza", 116 | "phone": 1231231122, 117 | "createdAt": "2018-08-11", 118 | "updatedAt": "2018-08-11" 119 | }, 120 | { 121 | "id": 2, 122 | "name": "2 Pac", 123 | "email": "twopac@gmail.com", 124 | "password": "$2a$10$5COzp14UCuBBPxqvxOAxNesRkbwLdtVdD24I9SJIat9Nxumg3z0WW", 125 | "phone": 1231231122, 126 | "createdAt": "2018-08-11", 127 | "updatedAt": "2018-08-11" 128 | } 129 | ] 130 | ``` 131 | 132 | * **Error Response:** 133 | 134 | * **Code:** 401 UNAUTHORIZED
135 | **Content:** `{ error : "users can be listed" }` 136 | ------------------------------------------------------------ 137 | * **URL** 138 | 139 | _https://api.zxsean.com/yelp_ 140 | 141 | * **Method:** 142 | 143 | `GET` 144 | 145 | * **URL Params** 146 | 147 | `term=[string]`, `lat=[double]`, `long=[double]`, `x-access-token=[string]` 148 | 149 | * **Success Response:** 150 | 151 | * **Code:** 200
152 | **Content:** 153 | ```json 154 | [ 155 | { 156 | "name": "Vero Pizza Napoletana", 157 | "url": "https://s3-media4.fl.yelpcdn.com/bphoto/OjoO-z3WBwRzlHifvP0vcA/o.jpg", 158 | "rating": 4, 159 | "price": "$$", 160 | "review_count": 156 161 | }, 162 | { 163 | "name": "Dewey's Pizza", 164 | "url": "https://s3-media1.fl.yelpcdn.com/bphoto/iOboHiGvLgp24eOkVRyEiQ/o.jpg", 165 | "rating": 4.5, 166 | "price": "$$", 167 | "review_count": 147 168 | } 169 | ] 170 | ``` 171 | 172 | * **Error Response:** 173 | 174 | * **Code:** 401 UNAUTHORIZED
175 | **Content:** `{ error : "business can be listed" }` 176 | ------------------------------------------------------------ 177 | # Continous Integration 178 | - The api is build on Bitrise and deployed to the dev server 179 | - If you are contributing and want to build the dev server, please DM [sean7218](https://twitter.com/sean7218) 180 | - The api test needs to be written and test needs to be running every day trigger on the Bitrise 181 | 182 | ### login terminated 183 | -------------------------------------------------------------------------------- /__tests__/user.test.js: -------------------------------------------------------------------------------- 1 | const userRouter = require("../routes/user"); 2 | const express = require("express"); 3 | const request = require("supertest"); 4 | 5 | jest.mock("../models"); 6 | 7 | const initApp = () => { 8 | const app = express(); 9 | app.use("/user", userRouter); 10 | return app; 11 | }; 12 | 13 | describe("GET /user", () => { 14 | test("It should fetch all users", async () => { 15 | const app = initApp(); 16 | const res = await request(app).get("/user"); 17 | expect(res.body).toEqual({ 18 | "createdAt": "2018-08-11", 19 | "email": "da@gmail.com", 20 | "id": 8, 21 | "name": "da", 22 | "password": "$2a$10$5Dx/1.SrUNsOpTCvTyvLCuxqqxVx.piqD5pMGVIPiNPp9UdDiB38O", 23 | "phone": 1231231122, 24 | "updatedAt": "2018-08-11" 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /__tests__/user_dev.test.js: -------------------------------------------------------------------------------- 1 | var request = require("request"); 2 | 3 | const fetchData = () => { 4 | return new Promise(function (resolve, reject) { 5 | request("http://localhost:3000/user", (err, res, body) => { 6 | if (err) { 7 | console.log(err); 8 | reject(err); 9 | } 10 | resolve({res: res, body: body}); 11 | }); 12 | }); 13 | }; 14 | 15 | describe("test the api endpoint", () => { 16 | test("it should get data for the user", () => { 17 | fetchData().then(obj => { 18 | expect(obj.res.statusCode).toBe(200); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var createError = require("http-errors"); 2 | var express = require("express"); 3 | var path = require("path"); 4 | var cookieParser = require("cookie-parser"); 5 | var logger = require("morgan"); 6 | 7 | var indexRouter = require("./routes/index"); 8 | var userRouter = require("./routes/user"); 9 | var s3Router = require("./routes/s3"); 10 | var yelpRouter = require("./routes/yelp"); 11 | var app = express(); 12 | 13 | // view engine setup 14 | app.set("views", path.join(__dirname, "views")); 15 | app.set("view engine", "pug"); 16 | 17 | app.use(logger("dev")); 18 | app.use(express.json()); 19 | app.use(express.urlencoded({ extended: false })); 20 | app.use(cookieParser()); 21 | app.use(express.static(path.join(__dirname, "public"))); 22 | 23 | app.use("/", indexRouter); 24 | app.use("/user", userRouter); 25 | app.use("/s3", s3Router); 26 | app.use("/yelp", yelpRouter); 27 | 28 | // catch 404 and forward to error handler 29 | app.use(function (req, res, next) { 30 | next(createError(404)); 31 | }); 32 | 33 | // error handler 34 | app.use(function (err, req, res, next) { 35 | // set locals, only providing error in development 36 | res.locals.message = err.message; 37 | res.locals.error = req.app.get("env") === "development" ? err : {}; 38 | 39 | // render the error page 40 | res.status(err.status || 500); 41 | res.render("error"); 42 | }); 43 | 44 | module.exports = app; 45 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require("../app"); 8 | var debug = require("debug")("ubereats-api:server"); 9 | var http = require("http"); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || "3000"); 16 | app.set("port", port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on("error", onError); 30 | server.on("listening", onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort (val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError (error) { 57 | if (error.syscall !== "listen") { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === "string" 62 | ? "Pipe " + port 63 | : "Port " + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case "EACCES": 68 | console.error(bind + " requires elevated privileges"); 69 | process.exit(1); 70 | break; 71 | case "EADDRINUSE": 72 | console.error(bind + " is already in use"); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening () { 85 | var addr = server.address(); 86 | var bind = typeof addr === "string" 87 | ? "pipe " + addr 88 | : "port " + addr.port; 89 | debug("Listening on " + bind); 90 | } 91 | -------------------------------------------------------------------------------- /config/config.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sean7218/ubereats-api/a168ac5abf65725cdc3e7108639149c0c63874bb/config/config.js -------------------------------------------------------------------------------- /controllers/auth/UserController.js: -------------------------------------------------------------------------------- 1 | 2 | var jwt = require("jsonwebtoken"); 3 | var bcrypt = require("bcryptjs"); 4 | var config = require("../../config/config")[process.env.NODE_ENV]; 5 | var verifyToken = require("./token"); 6 | 7 | var models = require("../../models"); 8 | 9 | const register = (req, res) => { 10 | var salt = bcrypt.genSaltSync(10); 11 | var hashedPassword = bcrypt.hashSync(req.body.password, salt); 12 | models.User.create({ 13 | name: req.body.name, 14 | email: req.body.email, 15 | password: hashedPassword, 16 | phone: req.body.phone 17 | }).then(function (user) { 18 | var token = jwt.sign({ id: user.id }, config.secret, { expiresIn: 86400 }); 19 | res.status(200).send({ message: `user ${req.body.email} has been added.`, auth: true, token: token }); 20 | }); 21 | }; 22 | 23 | const login = (req, res) => { 24 | models.User.findOne({ 25 | where: { email: req.body.email } 26 | }).then(function (user) { 27 | console.log(user.password); 28 | console.log(req.body.password); 29 | console.log(config.salt); 30 | var isPasswordValid = bcrypt.compareSync(req.body.password, user.password); 31 | if (!isPasswordValid) { 32 | return res.status(401).send({ auth: false, token: null }); 33 | } else { 34 | var token = jwt.sign({ id: user.id }, config.secret, { expiresIn: 86400 }); 35 | return res.status(200).send({ auth: true, token: token }); 36 | } 37 | }); 38 | }; 39 | 40 | const logout = (req, res) => { 41 | models.User.findOne({ 42 | where: { email: req.body.email } 43 | }).then(function (user) { 44 | // needs to set token expiration 45 | return res.status(200).send(`user ${user.email} has logout`); 46 | }); 47 | }; 48 | 49 | /** 50 | * @description check if the token is valid by giving the user info 51 | */ 52 | const verifyme = (req, res) => { 53 | console.log(2);// 54 | models.User.findById(req.userId).then((user) => { 55 | console.log(user); 56 | if (user) { 57 | res.status(200).send(user); 58 | } else { 59 | res.status(404).send("user can't be found"); 60 | } 61 | }); 62 | }; 63 | 64 | module.exports = { 65 | register, 66 | login, 67 | logout, 68 | verifyme, 69 | verifyToken 70 | }; 71 | -------------------------------------------------------------------------------- /controllers/auth/token.js: -------------------------------------------------------------------------------- 1 | var jwt = require("jsonwebtoken"); 2 | var config = require("../../config/config")[process.env.NODE_ENV]; 3 | 4 | /** 5 | * @description 6 | * middleware that verify the token before giving any access to resources 7 | */ 8 | function verifyToken (req, res, next) { 9 | var token = req.headers["x-access-token"]; 10 | if (!token) { 11 | return res.status(403).send({ auth: false, message: "Token Not Authorized." }); 12 | } else { 13 | console.log(token); 14 | jwt.verify(token, config.secret, function (err, decoded) { 15 | if (err) { return res.status(500).send({ auth: false, message: err }); } 16 | req.userId = decoded.id; 17 | next(); 18 | }); 19 | } 20 | } 21 | 22 | module.exports = verifyToken; 23 | -------------------------------------------------------------------------------- /controllers/s3/S3Controller.js: -------------------------------------------------------------------------------- 1 | var AWS = require("aws-sdk"); 2 | var config = require("../../config/config")[process.env.NODE_ENV]; 3 | var S3Client = {}; 4 | var fs = require("fs"); 5 | var path = require("path"); 6 | 7 | AWS.config.update({ 8 | signatureVersion: "v4" 9 | }); 10 | var s3 = new AWS.S3({ apiVersion: "2006-03-01" }); 11 | 12 | s3.config.update({ 13 | accessKeyId: config.accessKeyId, 14 | secretAccessKey: config.secretAccessKey, 15 | region: "us-east-2" 16 | 17 | }); 18 | 19 | const listObjects = (req, res) => { 20 | let bucket = req.body.bucket; 21 | let prefix = req.body.prefix; 22 | s3.listObjects({ 23 | Bucket: bucket, 24 | Delimiter: "", 25 | Prefix: prefix 26 | }, function (err, data) { 27 | console.log("listing objects"); 28 | if (err) { 29 | console.log("Error on listing objects: " + err); 30 | res.send(err); 31 | } else { 32 | console.log(data); 33 | res.send(data); 34 | } 35 | }); 36 | }; 37 | 38 | /** 39 | * @description 40 | * upload image to S3 Bucket 41 | * @param key String - the key for the S3 bucket 42 | * 43 | * @example 44 | * uploadImage('key: MISC.jpg'); 45 | */ 46 | const uploadImage = (req, res) => { 47 | let bucket = req.body.bucket; 48 | let key = req.body.key; 49 | let dir = path.join(__dirname, "../../public/images", key); 50 | let base64data = fs.readFileSync(dir); 51 | 52 | s3.putObject({ 53 | Bucket: bucket, 54 | Key: key, 55 | Body: base64data, 56 | ACL: "public-read" 57 | }, function (err, output) { 58 | if (err) { 59 | console.log(err); 60 | return res.send(err); 61 | } else { 62 | console.log(output); 63 | return res.send(output); 64 | } 65 | }); 66 | }; 67 | 68 | const downloadImage = (req, res) => { 69 | let bucket = req.body.bucket; 70 | let key = req.body.key; 71 | let dir = path.join(__dirname, "../../public/images", key); 72 | console.log(dir); 73 | s3.getObject({ 74 | Bucket: bucket, 75 | Key: key 76 | }, function (err, data) { 77 | if (err) { 78 | console.log(err); 79 | res.send(err); 80 | } else { 81 | fs.writeFileSync(dir, data.Body, { encoding: "binary" }); 82 | res.send("downloaded image"); 83 | } 84 | }); 85 | }; 86 | 87 | function getImageUrl (bucket, key) { 88 | return new Promise((resolve, reject) => { 89 | let params = { Bucket: bucket, Key: key }; 90 | s3.getObject(params, (err, obj) => { 91 | if (err || !obj) { 92 | reject(err); 93 | } else { 94 | s3.getSignedUrl("getObject", params, (err, url) => { 95 | if (err) { 96 | reject(err); 97 | } else { 98 | resolve(url.split("?")[0]); 99 | } 100 | }); // getSignedUrl 101 | } 102 | }); // getObject 103 | }); 104 | } 105 | 106 | S3Client = { 107 | listObjects, 108 | getImageUrl, 109 | uploadImage, 110 | downloadImage 111 | }; 112 | 113 | module.exports = S3Client; 114 | -------------------------------------------------------------------------------- /database/migrations/201808121200-create-user.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: (queryInterface, Sequelize) => { 4 | return queryInterface.createTable("users", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: Sequelize.INTEGER 10 | }, 11 | name: { 12 | type: Sequelize.STRING 13 | }, 14 | email: { 15 | type: Sequelize.STRING 16 | }, 17 | password: { 18 | type: Sequelize.STRING 19 | }, 20 | phone: { 21 | type: Sequelize.INTEGER 22 | }, 23 | createdAt: { 24 | allowNull: false, 25 | type: Sequelize.DATE 26 | }, 27 | updatedAt: { 28 | allowNull: false, 29 | type: Sequelize.DATE 30 | } 31 | }); 32 | }, 33 | down: (queryInterface, Sequelize) => { 34 | return queryInterface.dropTable("users"); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /database/mocks/user.js: -------------------------------------------------------------------------------- 1 | const users = [ 2 | { 3 | name: "Sean Smith", 4 | email: "sean@gmail.com", 5 | password: "123", 6 | phone: 5001118888 7 | }, 8 | { 9 | name: "John Smith", 10 | email: "john@gmail.com", 11 | password: "123", 12 | phone: 5118882222 13 | }, 14 | { 15 | name: "Bob Smith", 16 | email: "bob@gmail.com", 17 | password: "123", 18 | phone: 5001118888 19 | } 20 | ]; 21 | 22 | module.exports = users; 23 | -------------------------------------------------------------------------------- /database/scripts/user-generate.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO users ( 2 | `name`, 3 | `email`, 4 | `password`, 5 | `phone`) 6 | VALUES ( 7 | 'sean smith', 8 | 'sean@gmail.com', 9 | '123', 10 | '502000000'); -------------------------------------------------------------------------------- /database/scripts/user.sql: -------------------------------------------------------------------------------- 1 | -- /* 2 | -- * Script for generating the baseline database 3 | -- * StackerServerDB 4 | -- * by Sean Zhang 8/7/2018 5 | -- */ 6 | SHOW DATABASES; 7 | USE ubereatsdb; 8 | SHOW TABLES; 9 | 10 | CREATE TABLE IF NOT EXISTS users ( 11 | id INT(20) NOT NULL AUTO_INCREMENT, 12 | name VARCHAR(50) NOT NULL, 13 | email VARCHAR(50) NOT NULL, 14 | password VARCHAR(100) NOT NULL, 15 | phone INT(20) DEFAULT NULL, 16 | createdAt DATE, 17 | updatedAt DATE, 18 | PRIMARY KEY (id) 19 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -------------------------------------------------------------------------------- /models/__mocks__/index.js: -------------------------------------------------------------------------------- 1 | const db = {}; 2 | const User = {}; 3 | User.findById = () => { 4 | return new Promise((resolve, reject) => { 5 | resolve({ data: "mock data exist from User.findByID" }); 6 | }); 7 | }; 8 | User.findAll = () => { 9 | return new Promise((resolve, reject) => { 10 | resolve({ 11 | "createdAt": "2018-08-11", 12 | "email": "da@gmail.com", 13 | "id": 8, 14 | "name": "da", 15 | "password": "$2a$10$5Dx/1.SrUNsOpTCvTyvLCuxqqxVx.piqD5pMGVIPiNPp9UdDiB38O", 16 | "phone": 1231231122, 17 | "updatedAt": "2018-08-11" 18 | }); 19 | }); 20 | }; 21 | db.User = User; 22 | 23 | console.log("inside modes/__mock__/index.js"); 24 | module.exports = db; 25 | -------------------------------------------------------------------------------- /models/index.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | var Sequelize = require("sequelize"); 4 | var basename = path.basename(__filename); 5 | var config = require("../config/config.js")[process.env.NODE_ENV]; 6 | var db = {}; 7 | 8 | var dbConfig = { 9 | host: config.host, 10 | port: 3306, 11 | dialect: "mysql", 12 | logging: () => { console.log(` Sequelize Host: ${config.host}`); } 13 | }; 14 | 15 | console.log(`host: ${config.host} database connection established`); 16 | var sequelize = new Sequelize(config.database, config.username, config.password, dbConfig); 17 | 18 | fs 19 | .readdirSync(__dirname) 20 | .filter(file => { 21 | return (file.indexOf(".") !== 0) && (file !== basename) && (file.slice(-3) === ".js"); 22 | }) 23 | .forEach(file => { 24 | var model = sequelize["import"](path.join(__dirname, file)); 25 | var modelName = capFirstLetter(model.name); 26 | console.log(modelName); 27 | db[modelName] = model; 28 | }); 29 | 30 | Object.keys(db).forEach(modelName => { 31 | if (db[modelName].associate) { 32 | db[modelName].associate(db); 33 | } 34 | }); 35 | 36 | db.sequelize = sequelize; 37 | db.Sequelize = Sequelize; 38 | 39 | /** 40 | * @description 41 | * the database table is plural and small letters such as `users` 42 | * the model used in the Sequelize should be singular and capitalized such as `User` 43 | */ 44 | function capFirstLetter (model) { 45 | let cap = model.charAt(0).toUpperCase() + model.slice(1); 46 | return cap.slice(0, -1); 47 | } 48 | module.exports = db; 49 | -------------------------------------------------------------------------------- /models/user.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = (sequelize, DataTypes) => { 3 | var User = sequelize.define("users", { 4 | name: { 5 | type: DataTypes.STRING, 6 | allowNull: false 7 | }, 8 | email: { 9 | type: DataTypes.STRING, 10 | allowNull: false 11 | }, 12 | password: { 13 | type: DataTypes.STRING, 14 | allowNull: false 15 | }, 16 | phone: { 17 | type: DataTypes.INTEGER, 18 | allowNull: true, 19 | defaultValue: null 20 | }, 21 | createdAt: { 22 | type: DataTypes.DATE, 23 | allowNull: true, 24 | defaultValue: null 25 | } 26 | }); 27 | return User; 28 | }; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ubereats-api", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "NODE_ENV=local node ./bin/www", 7 | "test": "jest" 8 | }, 9 | "dependencies": { 10 | "aws-sdk": "^2.291.0", 11 | "axios": "^0.18.0", 12 | "bcryptjs": "^2.4.3", 13 | "body-parser": "^1.18.3", 14 | "cookie-parser": "~1.4.3", 15 | "debug": "~2.6.9", 16 | "express": "~4.16.0", 17 | "http-errors": "~1.6.2", 18 | "jsonwebtoken": "^8.3.0", 19 | "morgan": "~1.9.0", 20 | "mysql2": "^1.6.1", 21 | "pug": "2.0.0-beta11", 22 | "request": "^2.88.0", 23 | "sequelize": "^4.38.0" 24 | }, 25 | "devDependencies": { 26 | "eslint": "^5.3.0", 27 | "eslint-config-airbnb-base": "^13.1.0", 28 | "eslint-config-google": "^0.9.1", 29 | "eslint-config-standard": "^11.0.0", 30 | "eslint-plugin-import": "^2.14.0", 31 | "eslint-plugin-node": "^7.0.1", 32 | "eslint-plugin-promise": "^3.8.0", 33 | "eslint-plugin-standard": "^3.1.0", 34 | "jest": "^23.5.0", 35 | "supertest": "^3.1.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get("/", function (req, res, next) { 6 | res.render("index", { title: "Express" }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /routes/s3.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | // var models = require('../models') // not in use 4 | var bodyParser = require("body-parser"); 5 | var S3Controller = require("../controllers/s3/S3Controller"); 6 | 7 | router.use(bodyParser.urlencoded({ extended: true })); 8 | 9 | router.post("/getImageUrl", function (req, res) { 10 | let bucket = req.body.bucket; 11 | let key = req.body.key; 12 | console.log("bucket: " + bucket + ", key: " + key); 13 | S3Controller.getImageUrl(bucket, key).then(url => { 14 | console.log(url); 15 | res.status(200).send(url); 16 | }, err => { 17 | res.status(404).send(err); 18 | }); 19 | }); 20 | 21 | router.post("/listObjects", S3Controller.listObjects); 22 | router.post("/uploadImage", S3Controller.uploadImage); 23 | router.post("/downloadImage", S3Controller.downloadImage); 24 | 25 | module.exports = router; 26 | -------------------------------------------------------------------------------- /routes/user.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | var models = require("../models"); 4 | var bodyParser = require("body-parser"); 5 | var userController = require("../controllers/auth/UserController"); 6 | 7 | router.use(bodyParser.urlencoded({ extended: true })); 8 | 9 | router.get("/", function (req, res, next) { 10 | models.User.findAll().then(function (users) { 11 | res.json(users); 12 | }); 13 | }); 14 | 15 | router.get("/:id", function (req, res, next) { 16 | let email = req.params.email; 17 | console.log(email); 18 | models.User.findById(req.params.id).then(function (user) { 19 | return res.send(user); 20 | }); 21 | }); 22 | 23 | router.put("/:id", function (req, res) { 24 | models.User.findById(req.params.id) 25 | .then(function (user) { 26 | user.update({ 27 | name: req.body.name, 28 | phone: req.body.phone 29 | }); 30 | return res.send(`user ${req.body.name} updated`); 31 | }); 32 | }); 33 | 34 | router.delete("/:id", function (req, res) { 35 | models.User.destroy({ 36 | where: { 37 | id: req.params.id 38 | } 39 | }).then(function (user) { 40 | return res.send(`the user ${req.params.id} has been deleted`); 41 | }); 42 | }); 43 | 44 | router.post("/register", userController.register); 45 | router.post("/login", userController.login); 46 | router.post("/logout", userController.logout); 47 | router.get("/verify/me", userController.verifyToken, userController.verifyme); 48 | 49 | module.exports = router; 50 | -------------------------------------------------------------------------------- /routes/yelp.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | var axios = require("axios"); 4 | const config = require("../config/config")["dev"]; 5 | const verifyToken = require("../controllers/auth/token"); 6 | 7 | router.get("/", verifyToken, function (req, res, next) { 8 | console.log(req); 9 | const term = req.query.term || "restaurants"; 10 | const lat = req.query.lat || "37.786882"; 11 | const long = req.query.long || "-122.399972"; 12 | const aconfig = { 13 | method: "get", 14 | url: `https://api.yelp.com/v3/businesses/search?term=${term}&latitude=${lat}&longitude=${long}`, 15 | headers: { 16 | "Authorization": config.bear 17 | } 18 | }; 19 | axios(aconfig) 20 | .then(function (response) { 21 | const data = response.data.businesses.map((biz) => { 22 | let out = { 23 | name: biz.name, 24 | url: biz.image_url, 25 | rating: biz.rating, 26 | price: biz.price, 27 | review_count: biz.review_count 28 | }; 29 | return out; 30 | }); 31 | res.send(data); 32 | }) 33 | .catch(function (err) { 34 | console.log(err); 35 | res.send(err); 36 | }); 37 | }); 38 | 39 | module.exports = router; 40 | -------------------------------------------------------------------------------- /tests/sum.js: -------------------------------------------------------------------------------- 1 | function sum (a, b) { 2 | return a + b; 3 | } 4 | 5 | module.exports = sum; 6 | -------------------------------------------------------------------------------- /views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /views/index.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /views/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | --------------------------------------------------------------------------------