├── .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 | 
4 | 
5 | 
6 | 
7 | 
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 |
--------------------------------------------------------------------------------