├── .gitignore ├── README.md ├── app.ts ├── build ├── app.js ├── constants │ ├── constant.js │ └── error.js ├── controllers │ ├── add_ride_controller.js │ ├── calculate_ride_price_controller.js │ ├── driver_sign_in_controller.js │ ├── driver_sign_up_controller.js │ ├── find_ride_driver_controller.js │ ├── get_previous_rides_controller.js │ ├── get_user_info_controller.js │ ├── sign_in_controller.js │ └── sign_up_controller.js ├── middlewares │ └── token_middleware.js ├── models │ ├── Address.js │ ├── Driver.js │ ├── Price.js │ ├── Review.js │ ├── Ride.js │ └── User.js ├── routes │ ├── auth_router.js │ ├── ride_router.js │ └── user_router.js └── utils │ ├── helper.js │ └── validator.js ├── constants ├── constant.ts └── error.ts ├── controllers ├── add_ride_controller.ts ├── calculate_ride_price_controller.ts ├── driver_sign_in_controller.ts ├── driver_sign_up_controller.ts ├── find_ride_driver_controller.ts ├── get_previous_rides_controller.ts ├── get_user_info_controller.ts ├── sign_in_controller.ts └── sign_up_controller.ts ├── middlewares └── token_middleware.ts ├── models ├── Address.ts ├── Driver.ts ├── Price.ts ├── Review.ts ├── Ride.ts └── User.ts ├── nodemon.json ├── package-lock.json ├── package.json ├── routes ├── auth_router.ts ├── ride_router.ts └── user_router.ts ├── tsconfig.json └── utils ├── helper.ts └── validator.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | .ebextensions -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Saffar Backend 2 | ![Set of images](https://github.com/Saffar-Org/saffar_app/assets/37190888/9e9d9c71-e676-4850-9760-b27478defdaf) 3 | 4 | ## What is Saffar? 5 | A Test Taxi booking application. 6 | 7 | Saffar is an open source project to showcase the use of Flutter (Saffar app repository link [here](https://github.com/Saffar-Org/saffar_app/tree/dev)) with a Node JS backend along with TomTom maps service (Google Maps alternative. Link [here](https://www.tomtom.com/products/maps/)). 8 | 9 | The backend uses Node JS (code in TypeScript) along with MongoDB as database, Redis for caching and TomTom as map service (Google maps alternative, link [here](https://www.tomtom.com/products/maps/)). The Node server is hosted in AWS. 10 | 11 | ## Folder structure 12 | * **controller**: Contains all the controllers 13 | * **middlewares** Contains all the middlewares 14 | * **models**: Contains all the models 15 | * **routes**: Contains all the routes 16 | * **utils**: Contains the code for helpers and validators 17 | 18 | ## AWS Hosting 19 | The Node Server is hosted in AWS. For Node JS applications written in TypeScript, you have to first convert the TypeScript to JavaScript then deploy the code in AWS. I will be writing a tutorial on how to upload and deploy Node JS applications written in TypeScript in AWS Elastic Beanstalk so stay tuned. 20 | 21 | ## Other 22 | If you are interested to see examples of real world app code then do follow. It is always nice to connect with fellow developers. 23 | -------------------------------------------------------------------------------- /app.ts: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | import express from "express"; 3 | import mongoose from "mongoose"; 4 | import rideRouter from "./routes/ride_router"; 5 | import authRouter from "./routes/auth_router"; 6 | import userRouter from "./routes/user_router"; 7 | 8 | // Configuration for using .env file 9 | dotenv.config(); 10 | 11 | // Setting port to PORT in .env or 5000 if port in .env is null 12 | const PORT = process.env.PORT || 5000; 13 | 14 | const app = express(); 15 | 16 | // JSON body parser 17 | app.use(express.json()); 18 | app.use(express.urlencoded({ extended: false })); 19 | 20 | // Connecting to MongoDB 21 | if (process.env.MONGODB_CONNECTION_URL != undefined) { 22 | mongoose 23 | .connect(process.env.MONGODB_CONNECTION_URL) 24 | .catch((error: any) => console.log(error)); 25 | } 26 | 27 | // Auth router 28 | app.use("/api/auth", authRouter); 29 | 30 | // Ride router 31 | app.use("/api/ride", rideRouter); 32 | 33 | // User router 34 | app.use("/api/user", userRouter); 35 | 36 | // Listening to PORT 37 | app.listen(PORT, () => console.log(`Server is running in PORT ${PORT}`)); 38 | 39 | export { }; 40 | 41 | -------------------------------------------------------------------------------- /build/app.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const dotenv_1 = __importDefault(require("dotenv")); 7 | const express_1 = __importDefault(require("express")); 8 | const mongoose_1 = __importDefault(require("mongoose")); 9 | const ride_router_1 = __importDefault(require("./routes/ride_router")); 10 | const auth_router_1 = __importDefault(require("./routes/auth_router")); 11 | const user_router_1 = __importDefault(require("./routes/user_router")); 12 | // Configuration for using .env file 13 | dotenv_1.default.config(); 14 | // Setting port to PORT in .env or 5000 if port in .env is null 15 | const PORT = process.env.PORT || 5000; 16 | const app = (0, express_1.default)(); 17 | // JSON body parser 18 | app.use(express_1.default.json()); 19 | app.use(express_1.default.urlencoded({ extended: false })); 20 | // Connecting to MongoDB 21 | if (process.env.MONGODB_CONNECTION_URL != undefined) { 22 | mongoose_1.default 23 | .connect(process.env.MONGODB_CONNECTION_URL) 24 | .catch((error) => console.log(error)); 25 | } 26 | // Auth router 27 | app.use("/api/auth", auth_router_1.default); 28 | // Ride router 29 | app.use("/api/ride", ride_router_1.default); 30 | // User router 31 | app.use("/api/user", user_router_1.default); 32 | // Listening to PORT 33 | app.listen(PORT, () => console.log(`Server is running in PORT ${PORT}`)); 34 | -------------------------------------------------------------------------------- /build/constants/constant.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | class Constant { 3 | } 4 | /// Salt Rounds for encrpyting and dcrypting password 5 | Constant.saltRounds = 10; 6 | // 31 drivers phone numbers 7 | Constant.phoneNumbers = [ 8 | "098765419X", 9 | "987654220X", 10 | "876543121X", 11 | "765432022X", 12 | "654321923X", 13 | "543210824X", 14 | "432109725X", 15 | "321098626X", 16 | "210987527X", 17 | "109876428X", 18 | "098765329X", 19 | "987654130X", 20 | "876543031X", 21 | "765432932X", 22 | "654321833X", 23 | "543210734X", 24 | "432109635X", 25 | "321098536X", 26 | "210987437X", 27 | "109876338X", 28 | "098765239X", 29 | "987654040X", 30 | "876542941X", 31 | "765432842X", 32 | "654321743X", 33 | "543210644X", 34 | "432109545X", 35 | "321098446X", 36 | "210987347X", 37 | "109876248X", 38 | "098765149X", 39 | ]; 40 | Constant.names = [ 41 | "Aditi Sharma", 42 | "Akash Patel", 43 | "Aman Khan", 44 | "Ananya Gupta", 45 | "Anika Singh", 46 | "Anil Kapoor", 47 | "Arjun Sharma", 48 | "Arnav Mehta", 49 | "Asha Patel", 50 | "Ayush Verma", 51 | "Deepika Singhania", 52 | "Devika Choudhary", 53 | "Divya Khanna", 54 | "Gaurav Kapoor", 55 | "Gayatri Desai", 56 | "Ishaan Gupta", 57 | "Jaya Sharma", 58 | "Karishma Mehta", 59 | "Kunal Singh", 60 | "Leela Kapoor", 61 | "Madhav Desai", 62 | "Mahima Sharma", 63 | "Mohan Chaudhary", 64 | "Nandini Verma", 65 | "Natasha Singhania", 66 | "Neha Patel", 67 | "Niharika Gupta", 68 | "Pranav Kapoor", 69 | "Priya Sharma", 70 | "Rahul Verma", 71 | "Rajat Mehta", 72 | "Rishi Singh", 73 | "Ritu Kapoor", 74 | "Rohan Choudhary", 75 | "Sakshi Patel", 76 | "Sameer Sharma", 77 | "Sanaya Gupta", 78 | "Shivam Verma", 79 | "Simran Mehta", 80 | "Sonia Kapoor", 81 | "Suhana Singh", 82 | "Tanvi Sharma", 83 | "Tarun Verma", 84 | "Udit Patel", 85 | "Varun Kapoor", 86 | "Veena Sharma", 87 | "Vikram Choudhary", 88 | "Vishal Singh", 89 | "Yash Mehta", 90 | "Zara Kapoor", 91 | ]; 92 | Constant.vehicleNames = [ 93 | "Tata Indica", 94 | "Maruti Swift", 95 | "Mahindra Scorpio", 96 | "Hyundai i20", 97 | "Honda City", 98 | "Ford EcoSport", 99 | "Toyota Innova", 100 | "Renault Duster", 101 | "Volkswagen Polo", 102 | "Skoda Rapid", 103 | "Tata Nexon", 104 | "Maruti Baleno", 105 | "Mahindra XUV500", 106 | "Hyundai Creta", 107 | "Honda Amaze", 108 | "Ford Figo", 109 | "Toyota Fortuner", 110 | "Renault Kwid", 111 | "Volkswagen Vento", 112 | "Skoda Octavia", 113 | "Tata Tiago", 114 | "Maruti Vitara Brezza", 115 | "Mahindra Thar", 116 | "Hyundai Venue", 117 | "Honda WR-V", 118 | "Ford Endeavour", 119 | "Toyota Etios", 120 | "Renault Triber", 121 | "Volkswagen Tiguan", 122 | "Skoda Superb", 123 | "Tata Harrier", 124 | "Maruti Dzire", 125 | "Mahindra Bolero", 126 | "Hyundai Santro", 127 | "Honda Jazz", 128 | "Ford Aspire", 129 | "Toyota Camry", 130 | "Renault Captur", 131 | "Volkswagen T-Roc", 132 | "Skoda Kushaq", 133 | "Tata Safari", 134 | "Maruti Ertiga", 135 | "Mahindra Marazzo", 136 | "Hyundai Verna", 137 | "Honda Civic", 138 | "Ford Mustang", 139 | "Toyota Yaris", 140 | "Renault Zoe", 141 | "Volkswagen Polo GT", 142 | "Skoda Fabia", 143 | ]; 144 | Constant.vehicleNumbers = [ 145 | "IN12ABCDXX", 146 | "IN34GHIJXX", 147 | "IN56MNOPXX", 148 | "IN78STUVXX", 149 | "IN90YZ01XX", 150 | "IN45ABCFXX", 151 | "IN67GKLHXX", 152 | "IN89QRSMXX", 153 | "IN01VWXYXX", 154 | "IN23CDEFXX", 155 | "IN45IJKLXX", 156 | "IN67OPQRXX", 157 | "IN89UVWXXX", 158 | "IN23YZ01XX", 159 | "IN45ABCMXX", 160 | "IN67DEFPXX", 161 | "IN89GHIRXX", 162 | "IN01JKLUXX", 163 | "IN23MNOPXX", 164 | "IN45STUWXXX", 165 | "IN67XYZ0XX", 166 | "IN89ABCDXX", 167 | "IN01FGHIJXX", 168 | "IN23MNOQRXX", 169 | "IN45UVWXXX", 170 | "IN67ABCGXX", 171 | "IN89DEFLMXX", 172 | "IN01PQRSTXX", 173 | "IN23WXYZ0XX", 174 | "IN45ABCDXX", 175 | "IN67GHIJKXX", 176 | "IN89NOPQRXX", 177 | "IN01UVWXXX", 178 | "IN23YZ0XX", 179 | "IN45JKLMXX", 180 | "IN67PQRSXX", 181 | "IN89WXYZXX", 182 | "IN01ABCDEXX", 183 | "IN23HIJKXX", 184 | "IN45NOPXX", 185 | "IN67STUVXX", 186 | "IN89YZ01XX", 187 | "IN01ABCFXX", 188 | "IN23GHIJXX", 189 | "IN45MNOPXX", 190 | "IN67UVWXXX", 191 | "IN89ABCXX", 192 | "IN01FGHXX", 193 | "IN23KLMNXX", 194 | "IN45QRSTXX", 195 | ]; 196 | module.exports = Constant; 197 | -------------------------------------------------------------------------------- /build/constants/error.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /// Error codes and messages 3 | class Err { 4 | } 5 | Err.code = { 6 | EMPTY_PARAM: "EMPTY_PARAM", 7 | INVALID_PHONE: "INVALID_PHONE", 8 | INVALID_EMAIL: "INVALID_EMAIL", 9 | INVALID_PASSWORD: "INVALID_PASSWORD", 10 | INVALID_NAME: "INVALID_NAME", 11 | INVALID_VEHICLE_NAME: "INVALID_VEHICLE_NAME", 12 | INVALID_VEHICLE_NUMBER: "INVALID_VEHICLE_NUMBER", 13 | PHONE_ALREADY_EXISTS: "PHONE_ALREADY_EXISTS", 14 | EMAIL_ALREADY_EXISTS: "EMAIL_ALREADY_EXISTS", 15 | SERVER_ERROR: "SERVER_ERROR", 16 | NO_USER_WITH_PHONE: "NO_USER_WITH_PHONE", 17 | NO_USER_WITH_EMAIL: "NO_USER_WITH_EMAIL", 18 | NO_DRIVER_WITH_PHONE: "NO_DRIVER_WITH_PHONE", 19 | NO_DRIVER_WITH_EMAIL: "NO_DRIVER_WITH_EMAIL", 20 | WRONG_PASSWORD: "WRONG_PASSWORD", 21 | AUTHORIZATION_HEADER_MISSING: "AUTHORIZATION_HEADER_MISSING", 22 | INCORRECT_BEARER_TOKEN_FORMAT: "INCORRECT_BEARER_TOKEN_FORMAT", 23 | INVALID_BEARER_TOKEN: "INVALID_BEARER_TOKEN", 24 | NO_USER_WITH_ID: "NO_USER_WITH_ID", 25 | NO_PRICE_IN_DB: "NO_PRICE_IN_DB", 26 | }; 27 | Err.message = { 28 | EMPTY_PARAM: "One or more params are not present in the body of the POST request.", 29 | INVALID_PHONE: "Invalid phone.", 30 | INVALID_EMAIL: "Invalid email.", 31 | INVALID_PASSWORD: "Invalid password. Password must be at least 8 characters long.", 32 | INVALID_NAME: "Invalid name. Name can not be empty.", 33 | INVALID_VEHICLE_NAME: "Invalid vehicle name. Vehicle name can not be empty.", 34 | INVALID_VEHICLE_NUMBER: "Invalid vehicle number.", 35 | PHONE_ALREADY_EXISTS: "An user with this phone number is already present.", 36 | EMAIL_ALREADY_EXISTS: "An user with this email is already present.", 37 | SERVER_ERROR: "There was some problem in the server.", 38 | NO_USER_WITH_PHONE: "There is no user with this phone.", 39 | NO_USER_WITH_EMAIL: "There is no user with this email.", 40 | NO_DRIVER_WITH_PHONE: "There is no driver with this phone.", 41 | NO_DRIVER_WITH_EMAIL: "There is no driver with this email.", 42 | WRONG_PASSWORD: "Password is wrong.", 43 | AUTHORIZATION_HEADER_MISSING: "There is no authorization header in the request", 44 | INCORRECT_BEARER_TOKEN_FORMAT: 'Bearer token format is incorrect. It shoule be like "Bearer "', 45 | INVALID_BEARER_TOKEN: "Bearer token is either not active, expired or invalid", 46 | NO_USER_WITH_ID: "There is no user present with user id", 47 | NO_PRICE_IN_DB: "There is no price info in database.", 48 | }; 49 | module.exports = Err; 50 | -------------------------------------------------------------------------------- /build/controllers/add_ride_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | const error_1 = __importDefault(require("../constants/error")); 15 | const Ride_1 = __importDefault(require("../models/Ride")); 16 | const Address_1 = __importDefault(require("../models/Address")); 17 | /// Creates a Ride document and the source and destination document 18 | /// in MongoDB 19 | const addRideAndRideAddresses = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 20 | var _a; 21 | try { 22 | const userId = req.body.user_id; 23 | const driverId = req.body.driver_id; 24 | const sourceAddress = req.body.source_address; 25 | const destinationAddress = req.body.destination_address; 26 | const startTimeString = req.body.start_time; 27 | const endTimeString = req.body.end_time; 28 | const cancelled = (_a = req.body.cancelled) !== null && _a !== void 0 ? _a : false; 29 | const price = req.body.price; 30 | const discountPrice = req.body.discount_price; 31 | // If required params are not present then return 400 response 32 | if (userId === undefined || 33 | driverId === undefined || 34 | sourceAddress === undefined || 35 | destinationAddress === undefined || 36 | startTimeString === undefined || 37 | price === undefined) { 38 | return res.status(400).json({ 39 | error: { 40 | code: error_1.default.code.EMPTY_PARAM, 41 | message: error_1.default.message.EMPTY_PARAM, 42 | }, 43 | }); 44 | } 45 | // Date and Time from string 46 | const startTime = new Date(startTimeString); 47 | const endTime = new Date(endTimeString); 48 | // Creating the source address in MongoDB 49 | const sourceAddressDoc = yield Address_1.default.create({ 50 | place: sourceAddress["place"], 51 | street: sourceAddress["street"], 52 | state: sourceAddress["state"], 53 | country: sourceAddress["country"], 54 | lat: sourceAddress["lat"], 55 | lon: sourceAddress["lon"], 56 | pincode: sourceAddress["pincode"], 57 | }); 58 | // Creating the destination address in MongoDB 59 | const destinationAddressDoc = yield Address_1.default.create({ 60 | place: destinationAddress["place"], 61 | street: destinationAddress["street"], 62 | state: destinationAddress["state"], 63 | country: destinationAddress["country"], 64 | lat: destinationAddress["lat"], 65 | lon: destinationAddress["lon"], 66 | pincode: destinationAddress["pincode"], 67 | }); 68 | const sourceAddressId = sourceAddressDoc._id.toString(); 69 | const destinationAddressId = destinationAddressDoc._id.toString(); 70 | // Creating a ride in MongoDB 71 | yield Ride_1.default.create({ 72 | user: userId, 73 | driver: driverId, 74 | source_address: sourceAddressId, 75 | destination_address: destinationAddressId, 76 | start_time: startTime, 77 | end_time: endTime, 78 | cancelled: cancelled, 79 | price: price, 80 | discount_price: discountPrice, 81 | }); 82 | // Successful response after ride is created 83 | res.status(400).json({ 84 | message: "Ride created successfully.", 85 | }); 86 | } 87 | catch (error) { 88 | console.log(`Error in addRideAndRideAddresses: ${error}`); 89 | // Server error 90 | res.status(500).json({ 91 | error: { 92 | code: error_1.default.code.SERVER_ERROR, 93 | message: error_1.default.message.SERVER_ERROR, 94 | }, 95 | }); 96 | } 97 | }); 98 | module.exports = addRideAndRideAddresses; 99 | -------------------------------------------------------------------------------- /build/controllers/calculate_ride_price_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | const Price_1 = __importDefault(require("../models/Price")); 15 | const error_1 = __importDefault(require("../constants/error")); 16 | /// Gets price info from DB then calculates total ride price 17 | const getPriceInfoAndCalculateRidePrice = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 18 | try { 19 | const rideDistanceInKm = req.body.distance_in_km; 20 | // If ride's distance is not given by user then 21 | // return 400 response 22 | if (!rideDistanceInKm) { 23 | return res.status(400).json({ 24 | error: { 25 | code: error_1.default.code.EMPTY_PARAM, 26 | message: error_1.default.message.EMPTY_PARAM, 27 | }, 28 | }); 29 | } 30 | // Getting the first Price from MongoDB 31 | const price = yield Price_1.default.findOne(); 32 | // If price is not present in MongoDB then return 400 response 33 | if (!price) { 34 | return res.status(400).json({ 35 | error: { 36 | code: error_1.default.code.NO_PRICE_IN_DB, 37 | message: error_1.default.message.NO_PRICE_IN_DB, 38 | }, 39 | }); 40 | } 41 | const basePrice = price.base_price; 42 | const pricePerKm = price.price_per_km; 43 | // Calculate ride price 44 | const totalRideidePrice = basePrice + rideDistanceInKm * pricePerKm; 45 | // Return total ride price 46 | res.json({ 47 | total_price: totalRideidePrice, 48 | }); 49 | } 50 | catch (error) { 51 | console.log(`Error in getPriceInfoAndCalculateRidePrice: ${error}`); 52 | // Server error 53 | res.status(500).json({ 54 | error: { 55 | code: error_1.default.code.SERVER_ERROR, 56 | message: error_1.default.message.SERVER_ERROR, 57 | }, 58 | }); 59 | } 60 | }); 61 | module.exports = getPriceInfoAndCalculateRidePrice; 62 | -------------------------------------------------------------------------------- /build/controllers/driver_sign_in_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | const bcrypt = __importStar(require("bcrypt")); 38 | const jwt = __importStar(require("jsonwebtoken")); 39 | const error_1 = __importDefault(require("../constants/error")); 40 | const Driver_1 = __importDefault(require("../models/Driver")); 41 | const validator_1 = __importDefault(require("../utils/validator")); 42 | const driverSignIn = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 43 | try { 44 | const phone = req.body.phone; 45 | const password = req.body.password; 46 | // Checks if phone and password is present 47 | if (phone === undefined || password === undefined) { 48 | // If phone and password not present then return a 400 response 49 | return res.status(400).json({ 50 | error: { 51 | code: error_1.default.code.EMPTY_PARAM, 52 | message: error_1.default.message.EMPTY_PARAM, 53 | }, 54 | }); 55 | } 56 | // Checks if phone is valid 57 | if (!validator_1.default.validatePhone(phone)) { 58 | // If phone is not valid return a 400 response 59 | return res.status(400).json({ 60 | error: { 61 | code: error_1.default.code.INVALID_PHONE, 62 | message: error_1.default.message.INVALID_PHONE, 63 | }, 64 | }); 65 | } 66 | // Checks if password is valid 67 | if (!validator_1.default.validatePassword(password)) { 68 | // If password is not valid return a 400 response 69 | return res.status(400).json({ 70 | error: { 71 | code: error_1.default.code.INVALID_PASSWORD, 72 | message: error_1.default.message.INVALID_PASSWORD, 73 | }, 74 | }); 75 | } 76 | // Checking if a driver with this phone is present in the DB 77 | const driver = yield Driver_1.default.findOne({ phone: phone }); 78 | // If driver not present return a 400 response 79 | if (!driver) { 80 | return res.status(400).json({ 81 | error: { 82 | code: error_1.default.code.NO_DRIVER_WITH_PHONE, 83 | message: error_1.default.message.NO_DRIVER_WITH_PHONE, 84 | }, 85 | }); 86 | } 87 | const id = driver._id.toString(); 88 | const name = driver.name; 89 | const email = driver.email; 90 | const imageUrl = driver.image_url; 91 | const active = driver.active; 92 | const encryptedPassword = driver.password; 93 | const vehicleName = driver.vehicle_name; 94 | const vehicleNumber = driver.vehicle_number; 95 | // Compare password with encrypted password 96 | const passwordCorrect = yield bcrypt.compare(password, encryptedPassword); 97 | // If password not correct then return 400 response 98 | if (!passwordCorrect) { 99 | return res.status(400).json({ 100 | error: { 101 | code: error_1.default.code.WRONG_PASSWORD, 102 | message: error_1.default.message.WRONG_PASSWORD, 103 | }, 104 | }); 105 | } 106 | // Creating a token. Store this token and provide this token 107 | // when ever you want to get data for which authentication is required 108 | const token = jwt.sign({ id: id, phone: phone }, process.env.TOKEN_SECRET_KEY, { 109 | expiresIn: "1d", 110 | }); 111 | // Returning 200 response and driver data after driver is created in DB 112 | res.status(200).json({ 113 | message: "Driver signed in successfully", 114 | driver: { 115 | id: id, 116 | name: name, 117 | phone: phone, 118 | email: email, 119 | image_url: imageUrl, 120 | active: active, 121 | vehicle_name: vehicleName, 122 | vehicle_number: vehicleNumber, 123 | }, 124 | token: token, 125 | }); 126 | } 127 | catch (error) { 128 | console.log(`Error in sign in: ${error}`); 129 | // Server error 130 | res.status(500).json({ 131 | error: { 132 | code: error_1.default.code.SERVER_ERROR, 133 | message: error_1.default.message.SERVER_ERROR, 134 | }, 135 | }); 136 | } 137 | }); 138 | module.exports = driverSignIn; 139 | -------------------------------------------------------------------------------- /build/controllers/driver_sign_up_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | const bcrypt = __importStar(require("bcrypt")); 38 | const jwt = __importStar(require("jsonwebtoken")); 39 | const constant_1 = __importDefault(require("../constants/constant")); 40 | const error_1 = __importDefault(require("../constants/error")); 41 | const Driver_1 = __importDefault(require("../models/Driver")); 42 | const validator_1 = __importDefault(require("../utils/validator")); 43 | const driverSignUp = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 44 | try { 45 | // Generating a random id 46 | const name = req.body.name; 47 | const phone = req.body.phone; 48 | const password = req.body.password; 49 | const vehicleName = req.body.vehicle_name; 50 | const vehicleNumber = req.body.vehicle_number; 51 | // If name, phone, password, vehicle name or vehicle number 52 | // does not exist 53 | // then 400 response and error message and code 54 | // is returned. 55 | if (name === undefined || 56 | phone === undefined || 57 | password === undefined || 58 | vehicleName == undefined || 59 | vehicleNumber === undefined) { 60 | return res.status(400).json({ 61 | error: { 62 | code: error_1.default.code.EMPTY_PARAM, 63 | message: error_1.default.message.EMPTY_PARAM, 64 | }, 65 | }); 66 | } 67 | // Checking if name is valid 68 | if (!validator_1.default.validateName(name)) { 69 | return res.status(400).json({ 70 | error: { 71 | code: error_1.default.code.INVALID_NAME, 72 | message: error_1.default.message.INVALID_NAME, 73 | }, 74 | }); 75 | } 76 | // Checking if phone is valid 77 | if (!validator_1.default.validatePhone(phone)) { 78 | return res.status(400).json({ 79 | error: { 80 | code: error_1.default.code.INVALID_PHONE, 81 | message: error_1.default.message.INVALID_PHONE, 82 | }, 83 | }); 84 | } 85 | // Checking if password is valid 86 | if (!validator_1.default.validatePassword(password)) { 87 | return res.status(400).json({ 88 | error: { 89 | code: error_1.default.code.INVALID_PASSWORD, 90 | message: error_1.default.message.INVALID_PASSWORD, 91 | }, 92 | }); 93 | } 94 | // Checkinf if vehicle name is valid 95 | if (!validator_1.default.validateName(vehicleName)) { 96 | return res.status(400).json({ 97 | error: { 98 | code: error_1.default.code.INVALID_VEHICLE_NAME, 99 | message: error_1.default.message.INVALID_VEHICLE_NAME, 100 | }, 101 | }); 102 | } 103 | // Checkinf if vehicle number plate number is valid 104 | if (!validator_1.default.validateVehicleNumber(vehicleNumber)) { 105 | return res.status(400).json({ 106 | error: { 107 | code: error_1.default.code.INVALID_VEHICLE_NUMBER, 108 | message: error_1.default.message.INVALID_VEHICLE_NUMBER, 109 | }, 110 | }); 111 | } 112 | // Find if there is already a driver with this phone 113 | const oldDriver = yield Driver_1.default.findOne({ phone: phone }); 114 | // Returning phone already present error if driver with same phone 115 | // already present 116 | if (oldDriver) { 117 | return res.status(409).json({ 118 | error: { 119 | code: error_1.default.code.PHONE_ALREADY_EXISTS, 120 | message: error_1.default.message.PHONE_ALREADY_EXISTS, 121 | }, 122 | }); 123 | } 124 | // Hashing password 125 | const hashedPassword = yield bcrypt.hash(password, constant_1.default.saltRounds); 126 | // Creating a driver in MongoDB 127 | const driver = yield Driver_1.default.create({ 128 | name: name, 129 | phone: phone, 130 | password: hashedPassword, 131 | vehicle_name: vehicleName, 132 | vehicle_number: vehicleNumber, 133 | }); 134 | // MongoDB object _id 135 | const id = driver._id.toString(); 136 | // Creating a token. Store this token and provide this token 137 | // when ever you want to get data for which authentication is required 138 | const token = jwt.sign({ id: id, phone: phone }, process.env.TOKEN_SECRET_KEY, { 139 | expiresIn: "1d", 140 | }); 141 | // Returning 200 response and driver data after driver is created in DB 142 | res.status(200).json({ 143 | message: "Signed up and created driver successfully", 144 | driver: { 145 | id: id, 146 | name: name, 147 | phone: phone, 148 | }, 149 | token: token, 150 | }); 151 | } 152 | catch (error) { 153 | console.log(`Error in sign up: ${error}`); 154 | // Server error 155 | res.status(500).json({ 156 | error: { 157 | code: error_1.default.code.SERVER_ERROR, 158 | message: error_1.default.message.SERVER_ERROR, 159 | }, 160 | }); 161 | } 162 | }); 163 | module.exports = driverSignUp; 164 | -------------------------------------------------------------------------------- /build/controllers/find_ride_driver_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | const bcrypt = __importStar(require("bcrypt")); 38 | const axios_1 = __importDefault(require("axios")); 39 | const error_1 = __importDefault(require("../constants/error")); 40 | const Driver_1 = __importDefault(require("../models/Driver")); 41 | const helper_1 = __importDefault(require("../utils/helper")); 42 | const constant_1 = __importDefault(require("../constants/constant")); 43 | /// Finds a driver near the users location who is active. 44 | /// If no driver is available then a new driver is created 45 | /// and then the drive info is sent to the user. 46 | const findRideDriver = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 47 | try { 48 | const latitude = req.body.latitude; 49 | const longitude = req.body.longitude; 50 | const mapApiKey = req.body.map_api_key; 51 | // If latitude, longitude and map api key 52 | // are not present in req body 53 | // then send a 400 response 54 | if (!latitude || !longitude || !mapApiKey) { 55 | return res.status(400).json({ 56 | error: { 57 | code: error_1.default.code.EMPTY_PARAM, 58 | message: error_1.default.message.EMPTY_PARAM, 59 | }, 60 | }); 61 | } 62 | const changeLatitude = Math.random() <= 0.5; 63 | const sign = Math.random() <= 0.5 ? 1 : -1; 64 | // Adding or Subtracting 2 km from user latitude if [changeLatitude] is [true] 65 | const pointLatitude = latitude + (changeLatitude ? sign * 0.018 : 0); // 0.018 degree is 2 km 66 | // Adding or Subtracting 2 km from user longitude if [changeLatitude] is [false] 67 | const pointLongitude = longitude + (!changeLatitude ? sign * 0.018 : 0); // 0.018 degree is 2 km 68 | // Get the route info from point to user location 69 | const response = yield axios_1.default.get(`https://api.tomtom.com/routing/1/calculateRoute/${pointLatitude},${pointLongitude}:${latitude},${longitude}/json?key=${mapApiKey}`); 70 | // Route points 71 | const points = response.data["routes"][0]["legs"][0]["points"]; 72 | const driverSourceLatLon = points[0]; 73 | const driverDestinationLatLon = points[points.length - 1]; 74 | const driverSourceLatitude = Number.parseFloat(driverSourceLatLon["latitude"]); 75 | const driverSourceLongitude = Number.parseFloat(driverSourceLatLon["longitude"]); 76 | const driverDestinationLatitude = Number.parseFloat(driverDestinationLatLon["latitude"]); 77 | const driverDestinationLongitude = Number.parseFloat(driverDestinationLatLon["longitude"]); 78 | // Find a driver who is active 79 | let driver = yield Driver_1.default.findOne({ active: true }); 80 | // If no driver is active then create a new Driver 81 | if (!driver) { 82 | const index = helper_1.default.getRandomInt(constant_1.default.names.length); 83 | const name = constant_1.default.names[index]; 84 | const phone = helper_1.default.generatePhone(); 85 | const password = Date.now.toString(); 86 | const vehicleName = constant_1.default.vehicleNames[index]; 87 | const vehicleNumber = constant_1.default.vehicleNumbers[index]; 88 | // Hashing password 89 | const hashedPassword = yield bcrypt.hash(password, constant_1.default.saltRounds); 90 | // Creating a driver in MongoDB 91 | driver = yield Driver_1.default.create({ 92 | name: name, 93 | phone: phone, 94 | password: hashedPassword, 95 | vehicle_name: vehicleName, 96 | vehicle_number: vehicleNumber, 97 | }); 98 | } 99 | // Getting a driver field without the _id and __v fields 100 | const driverWithIdField = helper_1.default.getObjectWithIdInsteadOf_idAnd__v(driver); 101 | // Responding with a driver object and the source and destination 102 | // position of the driver 103 | res.json({ 104 | driver: driverWithIdField, 105 | source_position: { 106 | latitude: driverSourceLatitude, 107 | longitude: driverSourceLongitude, 108 | }, 109 | destination_position: { 110 | latitude: driverDestinationLatitude, 111 | longitude: driverDestinationLongitude, 112 | }, 113 | }); 114 | } 115 | catch (error) { 116 | console.log(`Error in createRideDriver: ${error}`); 117 | // Server error 118 | res.status(500).json({ 119 | error: { 120 | code: error_1.default.code.SERVER_ERROR, 121 | message: error_1.default.message.SERVER_ERROR, 122 | }, 123 | }); 124 | } 125 | }); 126 | module.exports = findRideDriver; 127 | -------------------------------------------------------------------------------- /build/controllers/get_previous_rides_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | const error_1 = __importDefault(require("../constants/error")); 15 | const Ride_1 = __importDefault(require("../models/Ride")); 16 | const User_1 = __importDefault(require("../models/User")); 17 | const Driver_1 = __importDefault(require("../models/Driver")); 18 | const Address_1 = __importDefault(require("../models/Address")); 19 | const helper_1 = __importDefault(require("../utils/helper")); 20 | /// Validates Bearer token then sends a response 21 | /// with all the previous rides of the user. 22 | /// If token is not valid, user id is not present, user 23 | /// is not present then returns a 400 response. Else 24 | /// returns a list of all the previous rides of the user. 25 | const getPreviousRidesOfUser = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 26 | try { 27 | const userId = req.body.user_id; 28 | // If user id not present return a 400 response 29 | if (!userId) { 30 | return res.status(400).json({ 31 | error: { 32 | code: error_1.default.code.EMPTY_PARAM, 33 | message: error_1.default.message.EMPTY_PARAM, 34 | }, 35 | }); 36 | } 37 | const currentDateTime = new Date(); 38 | // Finding a list of Rides ridden by the user then delete 39 | // the '__v' field and replace 40 | // the '_id' field to 'id' field. 41 | let allPreviousRidesByUser = (yield Ride_1.default.find({ 42 | user: userId, 43 | $or: [ 44 | { end_time: { $exists: false } }, 45 | { end_time: { $lt: currentDateTime } }, 46 | ], 47 | })).map((previousRide) => { 48 | return helper_1.default.getObjectWithIdInsteadOf_idAnd__v(previousRide); 49 | }); 50 | // Getting user, driver, source address, destination address and 51 | // deleting the '__v' field and replacing the '_id' field to 'id'. 52 | for (let index = 0; index < allPreviousRidesByUser.length; index++) { 53 | const userId = allPreviousRidesByUser[index].user; 54 | const user = yield User_1.default.findById(userId); 55 | const userWithIdField = helper_1.default.getObjectWithIdInsteadOf_idAnd__v(user); 56 | allPreviousRidesByUser[index].user = userWithIdField; 57 | const driverId = allPreviousRidesByUser[index].driver; 58 | const driver = yield Driver_1.default.findById(driverId); 59 | const driverWithIdField = helper_1.default.getObjectWithIdInsteadOf_idAnd__v(driver); 60 | allPreviousRidesByUser[index].driver = driverWithIdField; 61 | const sourceAddressId = allPreviousRidesByUser[index].source_address; 62 | const sourceAddress = yield Address_1.default.findById(sourceAddressId); 63 | const sourceAddressWithIdField = helper_1.default.getObjectWithIdInsteadOf_idAnd__v(sourceAddress); 64 | allPreviousRidesByUser[index].source_address = sourceAddressWithIdField; 65 | const destinationAddressId = allPreviousRidesByUser[index].destination_address; 66 | const destinationAddress = yield Address_1.default.findById(destinationAddressId); 67 | const destinationAddressWithIdField = helper_1.default.getObjectWithIdInsteadOf_idAnd__v(destinationAddress); 68 | allPreviousRidesByUser[index].destination_address = 69 | destinationAddressWithIdField; 70 | } 71 | // Sending a 200 response with all the previous rides 72 | // destination address to the user. 73 | res.status(200).json({ 74 | message: "All previous rides of the user fetched successfully.", 75 | previous_rides: allPreviousRidesByUser, 76 | }); 77 | } 78 | catch (error) { 79 | console.log(`Error in getPreviousRidesOfUser: ${error}`); 80 | // Server error 81 | res.status(500).json({ 82 | error: { 83 | code: error_1.default.code.SERVER_ERROR, 84 | message: error_1.default.message.SERVER_ERROR, 85 | }, 86 | }); 87 | } 88 | }); 89 | module.exports = getPreviousRidesOfUser; 90 | -------------------------------------------------------------------------------- /build/controllers/get_user_info_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | const Redis = __importStar(require("redis")); 38 | const error_1 = __importDefault(require("../constants/error")); 39 | const User_1 = __importDefault(require("../models/User")); 40 | const helper_1 = __importDefault(require("../utils/helper")); 41 | /// Gets user info from Redis server if present else gets user info 42 | /// from MongoDB 43 | const getUserInfo = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 44 | try { 45 | const id = req.body.id; 46 | // If no id i.e. user id is present then return a 400 47 | // response 48 | if (!id) { 49 | return res.status(400).json({ 50 | error: { 51 | code: error_1.default.code.EMPTY_PARAM, 52 | message: error_1.default.message.EMPTY_PARAM, 53 | }, 54 | }); 55 | } 56 | // Create a redis client 57 | const redisClient = Redis.createClient(); 58 | // Get user info from redis server 59 | const userInfo = yield redisClient.get(id); 60 | // If user info present in redis server then return user info 61 | if (userInfo) { 62 | return res.json({ 63 | user: userInfo, 64 | }); 65 | } 66 | // Find user info in MongoDB by using user id 67 | const user = yield User_1.default.findById(id); 68 | // If user not found in MongoDB then return a 400 response 69 | if (!user) { 70 | return res.status(400).json({ 71 | error: { 72 | code: error_1.default.code.NO_USER_WITH_ID, 73 | message: error_1.default.message.NO_USER_WITH_ID, 74 | }, 75 | }); 76 | } 77 | // Get user object without `_id` and `_v` 78 | const userWithout_idAnd_v = helper_1.default.getObjectWithIdInsteadOf_idAnd__v(user); 79 | // Set the user info value to the key id for 3600 seconds 80 | yield redisClient.setEx(id, 3600, JSON.stringify(userWithout_idAnd_v)); 81 | // Return the user info 82 | res.json({ 83 | user: userWithout_idAnd_v, 84 | }); 85 | } 86 | catch (error) { 87 | console.log(`Error in getUserInfo: ${error}`); 88 | // Server error 89 | res.status(500).json({ 90 | error: { 91 | code: error_1.default.code.SERVER_ERROR, 92 | message: error_1.default.message.SERVER_ERROR, 93 | }, 94 | }); 95 | } 96 | }); 97 | module.exports = getUserInfo; 98 | -------------------------------------------------------------------------------- /build/controllers/sign_in_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | const bcrypt = __importStar(require("bcrypt")); 38 | const jwt = __importStar(require("jsonwebtoken")); 39 | const error_1 = __importDefault(require("../constants/error")); 40 | const User_1 = __importDefault(require("../models/User")); 41 | const validator_1 = __importDefault(require("../utils/validator")); 42 | const signIn = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 43 | try { 44 | const phone = req.body.phone; 45 | const password = req.body.password; 46 | // Checks if phone and password is present 47 | if (phone === undefined || password === undefined) { 48 | // If phone and password not present then return a 400 response 49 | return res.status(400).json({ 50 | error: { 51 | code: error_1.default.code.EMPTY_PARAM, 52 | message: error_1.default.message.EMPTY_PARAM, 53 | }, 54 | }); 55 | } 56 | // Checks if phone is valid 57 | if (!validator_1.default.validatePhone(phone)) { 58 | // If phone is not valid return a 400 response 59 | return res.status(400).json({ 60 | error: { 61 | code: error_1.default.code.INVALID_PHONE, 62 | message: error_1.default.message.INVALID_PHONE, 63 | }, 64 | }); 65 | } 66 | // Checks if password is valid 67 | if (!validator_1.default.validatePassword(password)) { 68 | // If password is not valid return a 400 response 69 | return res.status(400).json({ 70 | error: { 71 | code: error_1.default.code.INVALID_PASSWORD, 72 | message: error_1.default.message.INVALID_PASSWORD, 73 | }, 74 | }); 75 | } 76 | // Checking if a user with this phone is present in the DB 77 | const user = yield User_1.default.findOne({ phone: phone }); 78 | // If user not present return a 400 response 79 | if (!user) { 80 | return res.status(400).json({ 81 | error: { 82 | code: error_1.default.code.NO_USER_WITH_PHONE, 83 | message: error_1.default.message.NO_USER_WITH_PHONE, 84 | }, 85 | }); 86 | } 87 | const id = user._id.toString(); 88 | const name = user.name; 89 | const encryptedPassword = user.password; 90 | const email = user.email; 91 | const imageUrl = user.image_url; 92 | // Compare password with encrypted password 93 | const passwordCorrect = yield bcrypt.compare(password, encryptedPassword); 94 | // If password not correct then return 400 response 95 | if (!passwordCorrect) { 96 | return res.status(400).json({ 97 | error: { 98 | code: error_1.default.code.WRONG_PASSWORD, 99 | message: error_1.default.message.WRONG_PASSWORD, 100 | }, 101 | }); 102 | } 103 | // Creating a token. Store this token and provide this token 104 | // when ever you want to get data for which authentication is required 105 | const token = jwt.sign({ id: id, phone: phone }, process.env.TOKEN_SECRET_KEY, { 106 | expiresIn: process.env.TOKEN_EXPIRY_TIME, 107 | }); 108 | // Returning 200 response and user data after user is created in DB 109 | res.status(200).json({ 110 | message: "User signed in successfully", 111 | user: { 112 | id: id, 113 | name: name, 114 | phone: phone, 115 | email: email, 116 | image_url: imageUrl, 117 | }, 118 | token: token, 119 | }); 120 | } 121 | catch (error) { 122 | console.log(`Error in sign in: ${error}`); 123 | // Server error 124 | res.status(500).json({ 125 | error: { 126 | code: error_1.default.code.SERVER_ERROR, 127 | message: error_1.default.message.SERVER_ERROR, 128 | }, 129 | }); 130 | } 131 | }); 132 | module.exports = signIn; 133 | -------------------------------------------------------------------------------- /build/controllers/sign_up_controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | const bcrypt = __importStar(require("bcrypt")); 38 | const jwt = __importStar(require("jsonwebtoken")); 39 | const constant_1 = __importDefault(require("../constants/constant")); 40 | const error_1 = __importDefault(require("../constants/error")); 41 | const User_1 = __importDefault(require("../models/User")); 42 | const validator_1 = __importDefault(require("../utils/validator")); 43 | const signUp = (req, res) => __awaiter(void 0, void 0, void 0, function* () { 44 | try { 45 | // Generating a random id 46 | const name = req.body.name; 47 | const phone = req.body.phone; 48 | const password = req.body.password; 49 | // If name, phone or password does not exist 50 | // then 400 response and error message and code 51 | // is returned. 52 | if (name === undefined || phone === undefined || password === undefined) { 53 | return res.status(400).json({ 54 | error: { 55 | code: error_1.default.code.EMPTY_PARAM, 56 | message: error_1.default.message.EMPTY_PARAM, 57 | }, 58 | }); 59 | } 60 | // Checking if name is valid 61 | if (!validator_1.default.validateName(name)) { 62 | return res.status(400).json({ 63 | error: { 64 | code: error_1.default.code.INVALID_NAME, 65 | message: error_1.default.message.INVALID_NAME, 66 | }, 67 | }); 68 | } 69 | // Checking if phone is valid 70 | if (!validator_1.default.validatePhone(phone)) { 71 | return res.status(400).json({ 72 | error: { 73 | code: error_1.default.code.INVALID_PHONE, 74 | message: error_1.default.message.INVALID_PHONE, 75 | }, 76 | }); 77 | } 78 | // Checking if password is valid 79 | if (!validator_1.default.validatePassword(password)) { 80 | return res.status(400).json({ 81 | error: { 82 | code: error_1.default.code.INVALID_PASSWORD, 83 | message: error_1.default.message.INVALID_PASSWORD, 84 | }, 85 | }); 86 | } 87 | // Find if there is already a user with this phone 88 | const oldUser = yield User_1.default.findOne({ phone: phone }); 89 | // Returning phone already present error if user with same phone 90 | // already present 91 | if (oldUser) { 92 | return res.status(409).json({ 93 | error: { 94 | code: error_1.default.code.PHONE_ALREADY_EXISTS, 95 | message: error_1.default.message.PHONE_ALREADY_EXISTS, 96 | }, 97 | }); 98 | } 99 | // Hashing password 100 | const hashedPassword = yield bcrypt.hash(password, constant_1.default.saltRounds); 101 | // Creating a user in MongoDB 102 | const user = yield User_1.default.create({ 103 | name: name, 104 | phone: phone, 105 | password: hashedPassword, 106 | }); 107 | // MongoDB object _id 108 | const id = user._id.toString(); 109 | // Creating a token. Store this token and provide this token 110 | // when ever you want to get data for which authentication is required 111 | const token = jwt.sign({ id: id, phone: phone }, process.env.TOKEN_SECRET_KEY, { 112 | expiresIn: process.env.TOKEN_EXPIRY_TIME, 113 | }); 114 | // Returning 200 response and user data after user is created in DB 115 | res.status(200).json({ 116 | message: "Signed up and created user successfully", 117 | user: { 118 | id: id, 119 | name: name, 120 | phone: phone, 121 | }, 122 | token: token, 123 | }); 124 | } 125 | catch (error) { 126 | console.log(`Error in sign up: ${error}`); 127 | // Server error 128 | res.status(500).json({ 129 | error: { 130 | code: error_1.default.code.SERVER_ERROR, 131 | message: error_1.default.message.SERVER_ERROR, 132 | }, 133 | }); 134 | } 135 | }); 136 | module.exports = signUp; 137 | -------------------------------------------------------------------------------- /build/middlewares/token_middleware.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | const error_1 = __importDefault(require("../constants/error")); 6 | const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); 7 | /// Validates Bearer token from request. 8 | /// If token does not exist or is not in the correct format 9 | /// or is not valid 10 | /// a 400 response is sent and [undefined] is returned 11 | const validateBearerToken = (req, res, next) => { 12 | const bearerToken = req.headers.authorization; 13 | // If there is no bearer token then sent 400 response 14 | if (!bearerToken) { 15 | res.status(400).json({ 16 | error: { 17 | code: error_1.default.code.AUTHORIZATION_HEADER_MISSING, 18 | message: error_1.default.message.AUTHORIZATION_HEADER_MISSING, 19 | }, 20 | }); 21 | throw `Token error: ${error_1.default.message.AUTHORIZATION_HEADER_MISSING}`; 22 | } 23 | // Splitting the "Bearer "" in a Array as ["Bearer", ""] 24 | const arr = bearerToken.split(" "); 25 | // If Bearer token format is not correct then send a 400 response 26 | if (arr.length < 2 || arr[0] !== "Bearer") { 27 | res.status(400).json({ 28 | error: { 29 | code: error_1.default.code.INCORRECT_BEARER_TOKEN_FORMAT, 30 | message: error_1.default.code.INCORRECT_BEARER_TOKEN_FORMAT, 31 | }, 32 | }); 33 | throw `Token error: ${error_1.default.message.INCORRECT_BEARER_TOKEN_FORMAT}`; 34 | } 35 | // The in "Bearer " 36 | const token = arr[1]; 37 | // If token is not valid throw a 400 response 38 | jsonwebtoken_1.default.verify(token, process.env.TOKEN_SECRET_KEY, (error) => { 39 | if (error) { 40 | res.status(400).json({ 41 | error: { 42 | code: error_1.default.code.INVALID_BEARER_TOKEN, 43 | message: error_1.default.message.INVALID_BEARER_TOKEN, 44 | }, 45 | }); 46 | throw `Token error: ${error_1.default.message.INVALID_BEARER_TOKEN}`; 47 | } 48 | }); 49 | if (next) { 50 | next(); 51 | } 52 | }; 53 | const tokenMiddleware = { validateBearerToken }; 54 | module.exports = tokenMiddleware; 55 | -------------------------------------------------------------------------------- /build/models/Address.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | const mongoose = __importStar(require("mongoose")); 26 | const addressSchema = new mongoose.Schema({ 27 | place: { 28 | type: String, 29 | }, 30 | street: { 31 | type: String, 32 | default: "Unnamed Road", 33 | }, 34 | state: { 35 | type: String, 36 | }, 37 | country: { 38 | type: String, 39 | }, 40 | lat: { 41 | type: Number, 42 | required: true, 43 | }, 44 | lon: { 45 | type: Number, 46 | required: true, 47 | }, 48 | pincode: { 49 | type: String, 50 | }, 51 | }); 52 | const address = mongoose.model("Address", addressSchema, "addresses"); 53 | module.exports = address; 54 | -------------------------------------------------------------------------------- /build/models/Driver.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __importDefault = (this && this.__importDefault) || function (mod) { 26 | return (mod && mod.__esModule) ? mod : { "default": mod }; 27 | }; 28 | const mongoose = __importStar(require("mongoose")); 29 | const validator_1 = __importDefault(require("../utils/validator")); 30 | const driverSchema = new mongoose.Schema({ 31 | name: { 32 | type: String, 33 | required: true, 34 | minLength: 1, 35 | maxLength: 1000, 36 | }, 37 | phone: { 38 | type: String, 39 | required: true, 40 | unique: true, 41 | minLength: 10, 42 | maxLength: 10, 43 | }, 44 | email: { 45 | type: String, 46 | unique: true, 47 | sparse: true, 48 | index: true, 49 | minLength: 5, 50 | maxLength: 254, 51 | validate: { 52 | validator: (email) => validator_1.default.validateEmail(email), 53 | message: (props) => `${props.value} is not a valid email.`, 54 | }, 55 | }, 56 | password: { 57 | type: String, 58 | required: true, 59 | minLength: 8, 60 | maxLength: 1000, 61 | validate: { 62 | validator: (password) => validator_1.default.validatePassword(password), 63 | message: (props) => `Password must be atleast 8 characters long.`, 64 | }, 65 | }, 66 | vehicle_name: { 67 | type: String, 68 | required: true, 69 | minLength: 1, 70 | maxLength: 1000, 71 | }, 72 | vehicle_number: { 73 | type: String, 74 | required: true, 75 | minLength: 1, 76 | maxLength: 1000, 77 | }, 78 | image_url: { 79 | type: String, 80 | minLength: 1, 81 | maxLength: 1000, 82 | }, 83 | active: { 84 | type: Boolean, 85 | default: true, 86 | }, 87 | }); 88 | const driver = mongoose.model("Driver", driverSchema, "drivers"); 89 | module.exports = driver; 90 | -------------------------------------------------------------------------------- /build/models/Price.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | const mongoose = __importStar(require("mongoose")); 26 | const priceSchema = new mongoose.Schema({ 27 | base_price: { 28 | type: Number, 29 | required: true, 30 | }, 31 | price_per_km: { 32 | type: Number, 33 | required: true, 34 | }, 35 | }); 36 | const price = mongoose.model('Price', priceSchema, "prices"); 37 | module.exports = price; 38 | -------------------------------------------------------------------------------- /build/models/Review.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | Object.defineProperty(exports, "__esModule", { value: true }); 26 | const mongoose = __importStar(require("mongoose")); 27 | const reviewSchema = new mongoose.Schema({ 28 | review: { 29 | type: String, 30 | required: true, 31 | minLength: 1, 32 | maxLength: 50000, 33 | }, 34 | stars: { 35 | type: Number, 36 | required: true, 37 | minLength: 0, 38 | maxLength: 5, 39 | }, 40 | user: { 41 | type: mongoose.SchemaTypes.ObjectId, 42 | required: true, 43 | ref: "User", 44 | }, 45 | driver: { 46 | type: mongoose.SchemaTypes.ObjectId, 47 | required: true, 48 | ref: "Driver", 49 | }, 50 | createdAt: { 51 | type: Date, 52 | required: true, 53 | }, 54 | updatedAt: { 55 | type: Date, 56 | required: true, 57 | }, 58 | }); 59 | const review = mongoose.model("Review", reviewSchema, "reviews"); 60 | -------------------------------------------------------------------------------- /build/models/Ride.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | const mongoose = __importStar(require("mongoose")); 26 | const rideSchema = new mongoose.Schema({ 27 | user: { 28 | type: mongoose.SchemaTypes.ObjectId, 29 | required: true, 30 | ref: "User", 31 | }, 32 | driver: { 33 | type: mongoose.SchemaTypes.ObjectId, 34 | required: true, 35 | ref: "Driver", 36 | }, 37 | source_address: { 38 | type: mongoose.SchemaTypes.ObjectId, 39 | required: true, 40 | ref: "Address", 41 | }, 42 | destination_address: { 43 | type: mongoose.SchemaTypes.ObjectId, 44 | required: true, 45 | ref: "Address", 46 | }, 47 | start_time: { 48 | type: Date, 49 | required: true, 50 | }, 51 | end_time: { 52 | type: Date, 53 | }, 54 | cancelled: { 55 | type: Boolean, 56 | default: false, 57 | }, 58 | price: { 59 | type: Number, 60 | default: 0.0, 61 | }, 62 | discount_price: { 63 | type: Number, 64 | }, 65 | }); 66 | const ride = mongoose.model("Ride", rideSchema, "rides"); 67 | module.exports = ride; 68 | -------------------------------------------------------------------------------- /build/models/User.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | const mongoose_1 = __importDefault(require("mongoose")); 6 | const validator_1 = __importDefault(require("../utils/validator")); 7 | const userSchema = new mongoose_1.default.Schema({ 8 | name: { 9 | type: String, 10 | required: true, 11 | minLength: 1, 12 | maxLength: 1000, 13 | }, 14 | phone: { 15 | type: String, 16 | required: true, 17 | unique: true, 18 | minLength: 10, 19 | maxLength: 10, 20 | validate: { 21 | validator: (phone) => validator_1.default.validatePhone(phone), 22 | message: (props) => `${props.value} is not a valid phone.`, 23 | }, 24 | }, 25 | email: { 26 | type: String, 27 | unique: true, 28 | sparse: true, 29 | index: true, 30 | minLength: 5, 31 | maxLength: 254, 32 | validate: { 33 | validator: (email) => validator_1.default.validateEmail(email), 34 | message: (props) => `${props.value} is not a valid email.`, 35 | }, 36 | }, 37 | password: { 38 | type: String, 39 | required: true, 40 | minLength: 8, 41 | maxLength: 1000, 42 | validate: { 43 | validator: (password) => validator_1.default.validatePassword(password), 44 | message: (props) => `Password must be atleast 8 characters long.`, 45 | }, 46 | }, 47 | image_url: { 48 | type: String, 49 | minLength: 1, 50 | maxLength: 1000, 51 | }, 52 | }); 53 | const user = mongoose_1.default.model("User", userSchema, "users"); 54 | module.exports = user; 55 | -------------------------------------------------------------------------------- /build/routes/auth_router.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | const express_1 = __importDefault(require("express")); 6 | const sign_up_controller_1 = __importDefault(require("../controllers/sign_up_controller")); 7 | const driver_sign_up_controller_1 = __importDefault(require("../controllers/driver_sign_up_controller")); 8 | const sign_in_controller_1 = __importDefault(require("../controllers/sign_in_controller")); 9 | const driver_sign_in_controller_1 = __importDefault(require("../controllers/driver_sign_in_controller")); 10 | const router = express_1.default.Router(); 11 | router.post("/sign_up", sign_up_controller_1.default); 12 | router.post("/driver_sign_up", driver_sign_up_controller_1.default); 13 | router.post("/sign_in", sign_in_controller_1.default); 14 | router.post("/driver_sign_in", driver_sign_in_controller_1.default); 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /build/routes/ride_router.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __importDefault = (this && this.__importDefault) || function (mod) { 26 | return (mod && mod.__esModule) ? mod : { "default": mod }; 27 | }; 28 | const express = __importStar(require("express")); 29 | const get_previous_rides_controller_1 = __importDefault(require("../controllers/get_previous_rides_controller")); 30 | const add_ride_controller_1 = __importDefault(require("../controllers/add_ride_controller")); 31 | const token_middleware_1 = __importDefault(require("../middlewares/token_middleware")); 32 | const calculate_ride_price_controller_1 = __importDefault(require("../controllers/calculate_ride_price_controller")); 33 | const find_ride_driver_controller_1 = __importDefault(require("../controllers/find_ride_driver_controller")); 34 | const router = express.Router(); 35 | router.get("/previous_rides", token_middleware_1.default.validateBearerToken, get_previous_rides_controller_1.default); 36 | router.post("/add_ride", token_middleware_1.default.validateBearerToken, add_ride_controller_1.default); 37 | router.get("/total_price", token_middleware_1.default.validateBearerToken, calculate_ride_price_controller_1.default); 38 | router.get("/find_ride_driver", token_middleware_1.default.validateBearerToken, find_ride_driver_controller_1.default); 39 | module.exports = router; 40 | -------------------------------------------------------------------------------- /build/routes/user_router.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __importDefault = (this && this.__importDefault) || function (mod) { 26 | return (mod && mod.__esModule) ? mod : { "default": mod }; 27 | }; 28 | const express = __importStar(require("express")); 29 | const token_middleware_1 = __importDefault(require("../middlewares/token_middleware")); 30 | const get_user_info_controller_1 = __importDefault(require("../controllers/get_user_info_controller")); 31 | const router = express.Router(); 32 | router.get("/", token_middleware_1.default.validateBearerToken, get_user_info_controller_1.default); 33 | module.exports = router; 34 | -------------------------------------------------------------------------------- /build/utils/helper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __rest = (this && this.__rest) || function (s, e) { 3 | var t = {}; 4 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) 5 | t[p] = s[p]; 6 | if (s != null && typeof Object.getOwnPropertySymbols === "function") 7 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { 8 | if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) 9 | t[p[i]] = s[p[i]]; 10 | } 11 | return t; 12 | }; 13 | /// Helper functions present here. 14 | class Helper { 15 | /// Gets a random int less than [max] 16 | static getRandomInt(max) { 17 | return Math.floor(Math.random() * max); 18 | } 19 | /// Generates a 10 digit phone number 20 | static generatePhone() { 21 | let phone = ""; 22 | for (let index = 0; index < 10; index++) { 23 | phone += this.getRandomInt(10); 24 | } 25 | return phone; 26 | } 27 | } 28 | /// This takes the object from the populate function and then 29 | /// deletes the '__v' field and 30 | /// changes the '_id' field to 'id' and returns a new 31 | /// object with the 'id' field. 32 | Helper.getObjectWithIdInsteadOf_idAnd__v = (doc) => { 33 | const _a = doc.toObject(), { _id, __v } = _a, rest = __rest(_a, ["_id", "__v"]); 34 | rest.id = _id.toString(); 35 | return rest; 36 | }; 37 | module.exports = Helper; 38 | -------------------------------------------------------------------------------- /build/utils/validator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | class Validator { 3 | /// Checks if name length is between 1 and 1000 4 | static validateName(name) { 5 | if (!name) { 6 | return false; 7 | } 8 | if (name.length < 0 || name.length > 1000) { 9 | return false; 10 | } 11 | return true; 12 | } 13 | /// Validates Email address 14 | static validateEmail(email) { 15 | // Checks if email is present or not 16 | if (!email) { 17 | return false; 18 | } 19 | // Checks if length of email is not more then 254 20 | if (email.length > 254) { 21 | return false; 22 | } 23 | // Checks if email matches the email RegExp 24 | const valid = this.emailRegex.test(email); 25 | if (!valid) { 26 | return false; 27 | } 28 | // Checks if part of email before '@' is not more then 64 29 | const emailParts = email.split("@"); 30 | if (emailParts[0].length > 64) { 31 | return false; 32 | } 33 | // Checks if each part of email after '@' which is separated by a '.' 34 | // is not more then 63 35 | const domainParts = emailParts[1].split("."); 36 | if (domainParts.some((part) => { 37 | return part.length > 63; 38 | })) { 39 | return false; 40 | } 41 | return true; 42 | } 43 | /// Checkinf if phone number length 10 and is numeric 44 | static validatePhone(phone) { 45 | if (!phone) { 46 | return false; 47 | } 48 | if (phone.length != 10) { 49 | return false; 50 | } 51 | return !isNaN(Number(phone)); 52 | } 53 | /// Validates if password length is between 8 and 1000 54 | static validatePassword(password) { 55 | if (!password) { 56 | return false; 57 | } 58 | return password.length >= 8; 59 | } 60 | /// Validates vehicle number plate number 61 | static validateVehicleNumber(vehicleNumber) { 62 | if (!vehicleNumber) { 63 | return false; 64 | } 65 | const numberPlateRegex = /^[A-Z]{2}[0-9]{2}[A-HJ-NP-Z]{1,2}[0-9]{4}$/; 66 | return numberPlateRegex.test(vehicleNumber); 67 | } 68 | } 69 | // Email Regular Expressing 70 | Validator.emailRegex = /^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/; 71 | module.exports = Validator; 72 | -------------------------------------------------------------------------------- /constants/constant.ts: -------------------------------------------------------------------------------- 1 | class Constant { 2 | /// Salt Rounds for encrpyting and dcrypting password 3 | static saltRounds: number = 10; 4 | 5 | // 31 drivers phone numbers 6 | static phoneNumbers: string[] = [ 7 | "098765419X", 8 | "987654220X", 9 | "876543121X", 10 | "765432022X", 11 | "654321923X", 12 | "543210824X", 13 | "432109725X", 14 | "321098626X", 15 | "210987527X", 16 | "109876428X", 17 | "098765329X", 18 | "987654130X", 19 | "876543031X", 20 | "765432932X", 21 | "654321833X", 22 | "543210734X", 23 | "432109635X", 24 | "321098536X", 25 | "210987437X", 26 | "109876338X", 27 | "098765239X", 28 | "987654040X", 29 | "876542941X", 30 | "765432842X", 31 | "654321743X", 32 | "543210644X", 33 | "432109545X", 34 | "321098446X", 35 | "210987347X", 36 | "109876248X", 37 | "098765149X", 38 | ]; 39 | 40 | static names: string[] = [ 41 | "Aditi Sharma", 42 | "Akash Patel", 43 | "Aman Khan", 44 | "Ananya Gupta", 45 | "Anika Singh", 46 | "Anil Kapoor", 47 | "Arjun Sharma", 48 | "Arnav Mehta", 49 | "Asha Patel", 50 | "Ayush Verma", 51 | "Deepika Singhania", 52 | "Devika Choudhary", 53 | "Divya Khanna", 54 | "Gaurav Kapoor", 55 | "Gayatri Desai", 56 | "Ishaan Gupta", 57 | "Jaya Sharma", 58 | "Karishma Mehta", 59 | "Kunal Singh", 60 | "Leela Kapoor", 61 | "Madhav Desai", 62 | "Mahima Sharma", 63 | "Mohan Chaudhary", 64 | "Nandini Verma", 65 | "Natasha Singhania", 66 | "Neha Patel", 67 | "Niharika Gupta", 68 | "Pranav Kapoor", 69 | "Priya Sharma", 70 | "Rahul Verma", 71 | "Rajat Mehta", 72 | "Rishi Singh", 73 | "Ritu Kapoor", 74 | "Rohan Choudhary", 75 | "Sakshi Patel", 76 | "Sameer Sharma", 77 | "Sanaya Gupta", 78 | "Shivam Verma", 79 | "Simran Mehta", 80 | "Sonia Kapoor", 81 | "Suhana Singh", 82 | "Tanvi Sharma", 83 | "Tarun Verma", 84 | "Udit Patel", 85 | "Varun Kapoor", 86 | "Veena Sharma", 87 | "Vikram Choudhary", 88 | "Vishal Singh", 89 | "Yash Mehta", 90 | "Zara Kapoor", 91 | ]; 92 | 93 | static vehicleNames: string[] = [ 94 | "Tata Indica", 95 | "Maruti Swift", 96 | "Mahindra Scorpio", 97 | "Hyundai i20", 98 | "Honda City", 99 | "Ford EcoSport", 100 | "Toyota Innova", 101 | "Renault Duster", 102 | "Volkswagen Polo", 103 | "Skoda Rapid", 104 | "Tata Nexon", 105 | "Maruti Baleno", 106 | "Mahindra XUV500", 107 | "Hyundai Creta", 108 | "Honda Amaze", 109 | "Ford Figo", 110 | "Toyota Fortuner", 111 | "Renault Kwid", 112 | "Volkswagen Vento", 113 | "Skoda Octavia", 114 | "Tata Tiago", 115 | "Maruti Vitara Brezza", 116 | "Mahindra Thar", 117 | "Hyundai Venue", 118 | "Honda WR-V", 119 | "Ford Endeavour", 120 | "Toyota Etios", 121 | "Renault Triber", 122 | "Volkswagen Tiguan", 123 | "Skoda Superb", 124 | "Tata Harrier", 125 | "Maruti Dzire", 126 | "Mahindra Bolero", 127 | "Hyundai Santro", 128 | "Honda Jazz", 129 | "Ford Aspire", 130 | "Toyota Camry", 131 | "Renault Captur", 132 | "Volkswagen T-Roc", 133 | "Skoda Kushaq", 134 | "Tata Safari", 135 | "Maruti Ertiga", 136 | "Mahindra Marazzo", 137 | "Hyundai Verna", 138 | "Honda Civic", 139 | "Ford Mustang", 140 | "Toyota Yaris", 141 | "Renault Zoe", 142 | "Volkswagen Polo GT", 143 | "Skoda Fabia", 144 | ]; 145 | 146 | static vehicleNumbers: string[] = [ 147 | "IN12ABCDXX", 148 | "IN34GHIJXX", 149 | "IN56MNOPXX", 150 | "IN78STUVXX", 151 | "IN90YZ01XX", 152 | "IN45ABCFXX", 153 | "IN67GKLHXX", 154 | "IN89QRSMXX", 155 | "IN01VWXYXX", 156 | "IN23CDEFXX", 157 | "IN45IJKLXX", 158 | "IN67OPQRXX", 159 | "IN89UVWXXX", 160 | "IN23YZ01XX", 161 | "IN45ABCMXX", 162 | "IN67DEFPXX", 163 | "IN89GHIRXX", 164 | "IN01JKLUXX", 165 | "IN23MNOPXX", 166 | "IN45STUWXXX", 167 | "IN67XYZ0XX", 168 | "IN89ABCDXX", 169 | "IN01FGHIJXX", 170 | "IN23MNOQRXX", 171 | "IN45UVWXXX", 172 | "IN67ABCGXX", 173 | "IN89DEFLMXX", 174 | "IN01PQRSTXX", 175 | "IN23WXYZ0XX", 176 | "IN45ABCDXX", 177 | "IN67GHIJKXX", 178 | "IN89NOPQRXX", 179 | "IN01UVWXXX", 180 | "IN23YZ0XX", 181 | "IN45JKLMXX", 182 | "IN67PQRSXX", 183 | "IN89WXYZXX", 184 | "IN01ABCDEXX", 185 | "IN23HIJKXX", 186 | "IN45NOPXX", 187 | "IN67STUVXX", 188 | "IN89YZ01XX", 189 | "IN01ABCFXX", 190 | "IN23GHIJXX", 191 | "IN45MNOPXX", 192 | "IN67UVWXXX", 193 | "IN89ABCXX", 194 | "IN01FGHXX", 195 | "IN23KLMNXX", 196 | "IN45QRSTXX", 197 | ]; 198 | } 199 | 200 | export = Constant; 201 | -------------------------------------------------------------------------------- /constants/error.ts: -------------------------------------------------------------------------------- 1 | /// Error codes and messages 2 | class Err { 3 | static code = { 4 | EMPTY_PARAM: "EMPTY_PARAM", 5 | INVALID_PHONE: "INVALID_PHONE", 6 | INVALID_EMAIL: "INVALID_EMAIL", 7 | INVALID_PASSWORD: "INVALID_PASSWORD", 8 | INVALID_NAME: "INVALID_NAME", 9 | INVALID_VEHICLE_NAME: "INVALID_VEHICLE_NAME", 10 | INVALID_VEHICLE_NUMBER: "INVALID_VEHICLE_NUMBER", 11 | PHONE_ALREADY_EXISTS: "PHONE_ALREADY_EXISTS", 12 | EMAIL_ALREADY_EXISTS: "EMAIL_ALREADY_EXISTS", 13 | SERVER_ERROR: "SERVER_ERROR", 14 | NO_USER_WITH_PHONE: "NO_USER_WITH_PHONE", 15 | NO_USER_WITH_EMAIL: "NO_USER_WITH_EMAIL", 16 | NO_DRIVER_WITH_PHONE: "NO_DRIVER_WITH_PHONE", 17 | NO_DRIVER_WITH_EMAIL: "NO_DRIVER_WITH_EMAIL", 18 | WRONG_PASSWORD: "WRONG_PASSWORD", 19 | AUTHORIZATION_HEADER_MISSING: "AUTHORIZATION_HEADER_MISSING", 20 | INCORRECT_BEARER_TOKEN_FORMAT: "INCORRECT_BEARER_TOKEN_FORMAT", 21 | INVALID_BEARER_TOKEN: "INVALID_BEARER_TOKEN", 22 | NO_USER_WITH_ID: "NO_USER_WITH_ID", 23 | NO_PRICE_IN_DB: "NO_PRICE_IN_DB", 24 | }; 25 | 26 | static message = { 27 | EMPTY_PARAM: 28 | "One or more params are not present in the body of the POST request.", 29 | INVALID_PHONE: "Invalid phone.", 30 | INVALID_EMAIL: "Invalid email.", 31 | INVALID_PASSWORD: 32 | "Invalid password. Password must be at least 8 characters long.", 33 | INVALID_NAME: "Invalid name. Name can not be empty.", 34 | INVALID_VEHICLE_NAME: "Invalid vehicle name. Vehicle name can not be empty.", 35 | INVALID_VEHICLE_NUMBER: "Invalid vehicle number.", 36 | PHONE_ALREADY_EXISTS: "An user with this phone number is already present.", 37 | EMAIL_ALREADY_EXISTS: "An user with this email is already present.", 38 | SERVER_ERROR: "There was some problem in the server.", 39 | NO_USER_WITH_PHONE: "There is no user with this phone.", 40 | NO_USER_WITH_EMAIL: "There is no user with this email.", 41 | NO_DRIVER_WITH_PHONE: "There is no driver with this phone.", 42 | NO_DRIVER_WITH_EMAIL: "There is no driver with this email.", 43 | WRONG_PASSWORD: "Password is wrong.", 44 | AUTHORIZATION_HEADER_MISSING: "There is no authorization header in the request", 45 | INCORRECT_BEARER_TOKEN_FORMAT: 'Bearer token format is incorrect. It shoule be like "Bearer "', 46 | INVALID_BEARER_TOKEN: "Bearer token is either not active, expired or invalid", 47 | NO_USER_WITH_ID: "There is no user present with user id", 48 | NO_PRICE_IN_DB: "There is no price info in database.", 49 | }; 50 | } 51 | 52 | export = Err; 53 | -------------------------------------------------------------------------------- /controllers/add_ride_controller.ts: -------------------------------------------------------------------------------- 1 | import Err from "../constants/error"; 2 | import Ride from "../models/Ride"; 3 | import Address from "../models/Address"; 4 | 5 | /// Creates a Ride document and the source and destination document 6 | /// in MongoDB 7 | const addRideAndRideAddresses = async (req: any, res: any) => { 8 | try { 9 | const userId: string = req.body.user_id; 10 | const driverId: string = req.body.driver_id; 11 | const sourceAddress: any = req.body.source_address; 12 | const destinationAddress: any = req.body.destination_address; 13 | const startTimeString: string = req.body.start_time; 14 | const endTimeString: string = req.body.end_time; 15 | const cancelled: boolean = req.body.cancelled ?? false; 16 | const price: number = req.body.price; 17 | const discountPrice: number = req.body.discount_price; 18 | 19 | // If required params are not present then return 400 response 20 | if ( 21 | userId === undefined || 22 | driverId === undefined || 23 | sourceAddress === undefined || 24 | destinationAddress === undefined || 25 | startTimeString === undefined || 26 | price === undefined 27 | ) { 28 | return res.status(400).json({ 29 | error: { 30 | code: Err.code.EMPTY_PARAM, 31 | message: Err.message.EMPTY_PARAM, 32 | }, 33 | }); 34 | } 35 | 36 | // Date and Time from string 37 | const startTime = new Date(startTimeString); 38 | const endTime = new Date(endTimeString); 39 | 40 | // Creating the source address in MongoDB 41 | const sourceAddressDoc = await Address.create({ 42 | place: sourceAddress["place"], 43 | street: sourceAddress["street"], 44 | state: sourceAddress["state"], 45 | country: sourceAddress["country"], 46 | lat: sourceAddress["lat"], 47 | lon: sourceAddress["lon"], 48 | pincode: sourceAddress["pincode"], 49 | }); 50 | 51 | // Creating the destination address in MongoDB 52 | const destinationAddressDoc = await Address.create({ 53 | place: destinationAddress["place"], 54 | street: destinationAddress["street"], 55 | state: destinationAddress["state"], 56 | country: destinationAddress["country"], 57 | lat: destinationAddress["lat"], 58 | lon: destinationAddress["lon"], 59 | pincode: destinationAddress["pincode"], 60 | }); 61 | 62 | const sourceAddressId: string = sourceAddressDoc._id.toString(); 63 | const destinationAddressId: string = destinationAddressDoc._id.toString(); 64 | 65 | // Creating a ride in MongoDB 66 | await Ride.create({ 67 | user: userId, 68 | driver: driverId, 69 | source_address: sourceAddressId, 70 | destination_address: destinationAddressId, 71 | start_time: startTime, 72 | end_time: endTime, 73 | cancelled: cancelled, 74 | price: price, 75 | discount_price: discountPrice, 76 | }); 77 | 78 | // Successful response after ride is created 79 | res.status(400).json({ 80 | message: "Ride created successfully.", 81 | }); 82 | } catch (error) { 83 | console.log(`Error in addRideAndRideAddresses: ${error}`); 84 | 85 | // Server error 86 | res.status(500).json({ 87 | error: { 88 | code: Err.code.SERVER_ERROR, 89 | message: Err.message.SERVER_ERROR, 90 | }, 91 | }); 92 | } 93 | }; 94 | 95 | export = addRideAndRideAddresses; 96 | -------------------------------------------------------------------------------- /controllers/calculate_ride_price_controller.ts: -------------------------------------------------------------------------------- 1 | import Price from "../models/Price"; 2 | import Err from "../constants/error"; 3 | 4 | /// Gets price info from DB then calculates total ride price 5 | const getPriceInfoAndCalculateRidePrice = async (req: any, res: any) => { 6 | try { 7 | const rideDistanceInKm = req.body.distance_in_km; 8 | 9 | // If ride's distance is not given by user then 10 | // return 400 response 11 | if (!rideDistanceInKm) { 12 | return res.status(400).json({ 13 | error: { 14 | code: Err.code.EMPTY_PARAM, 15 | message: Err.message.EMPTY_PARAM, 16 | }, 17 | }); 18 | } 19 | 20 | // Getting the first Price from MongoDB 21 | const price = await Price.findOne(); 22 | 23 | // If price is not present in MongoDB then return 400 response 24 | if (!price) { 25 | return res.status(400).json({ 26 | error: { 27 | code: Err.code.NO_PRICE_IN_DB, 28 | message: Err.message.NO_PRICE_IN_DB, 29 | }, 30 | }); 31 | } 32 | 33 | const basePrice: number = price.base_price; 34 | const pricePerKm: number = price.price_per_km; 35 | 36 | // Calculate ride price 37 | const totalRideidePrice: number = basePrice + rideDistanceInKm * pricePerKm; 38 | 39 | // Return total ride price 40 | res.json({ 41 | total_price: totalRideidePrice, 42 | }); 43 | } catch (error) { 44 | console.log(`Error in getPriceInfoAndCalculateRidePrice: ${error}`); 45 | 46 | // Server error 47 | res.status(500).json({ 48 | error: { 49 | code: Err.code.SERVER_ERROR, 50 | message: Err.message.SERVER_ERROR, 51 | }, 52 | }); 53 | } 54 | }; 55 | 56 | export = getPriceInfoAndCalculateRidePrice; 57 | -------------------------------------------------------------------------------- /controllers/driver_sign_in_controller.ts: -------------------------------------------------------------------------------- 1 | import * as bcrypt from "bcrypt"; 2 | import * as jwt from "jsonwebtoken"; 3 | import Err from "../constants/error"; 4 | import Driver from "../models/Driver"; 5 | import Validator from "../utils/validator"; 6 | 7 | const driverSignIn = async (req: any, res: any) => { 8 | try { 9 | const phone: string = req.body.phone; 10 | const password: string = req.body.password; 11 | 12 | // Checks if phone and password is present 13 | if (phone === undefined || password === undefined) { 14 | // If phone and password not present then return a 400 response 15 | return res.status(400).json({ 16 | error: { 17 | code: Err.code.EMPTY_PARAM, 18 | message: Err.message.EMPTY_PARAM, 19 | }, 20 | }); 21 | } 22 | 23 | // Checks if phone is valid 24 | if (!Validator.validatePhone(phone)) { 25 | // If phone is not valid return a 400 response 26 | return res.status(400).json({ 27 | error: { 28 | code: Err.code.INVALID_PHONE, 29 | message: Err.message.INVALID_PHONE, 30 | }, 31 | }); 32 | } 33 | 34 | // Checks if password is valid 35 | if (!Validator.validatePassword(password)) { 36 | // If password is not valid return a 400 response 37 | return res.status(400).json({ 38 | error: { 39 | code: Err.code.INVALID_PASSWORD, 40 | message: Err.message.INVALID_PASSWORD, 41 | }, 42 | }); 43 | } 44 | 45 | // Checking if a driver with this phone is present in the DB 46 | const driver = await Driver.findOne({ phone: phone }); 47 | 48 | // If driver not present return a 400 response 49 | if (!driver) { 50 | return res.status(400).json({ 51 | error: { 52 | code: Err.code.NO_DRIVER_WITH_PHONE, 53 | message: Err.message.NO_DRIVER_WITH_PHONE, 54 | }, 55 | }); 56 | } 57 | 58 | const id: string = driver._id.toString() as string; 59 | const name: string = driver.name as string; 60 | const email: string | undefined = driver.email; 61 | const imageUrl: string | undefined = driver.image_url; 62 | const active: boolean = driver.active; 63 | const encryptedPassword: string = driver.password; 64 | const vehicleName: string = driver.vehicle_name; 65 | const vehicleNumber: string = driver.vehicle_number; 66 | 67 | // Compare password with encrypted password 68 | const passwordCorrect: boolean = await bcrypt.compare( 69 | password, 70 | encryptedPassword 71 | ); 72 | 73 | // If password not correct then return 400 response 74 | if (!passwordCorrect) { 75 | return res.status(400).json({ 76 | error: { 77 | code: Err.code.WRONG_PASSWORD, 78 | message: Err.message.WRONG_PASSWORD, 79 | }, 80 | }); 81 | } 82 | 83 | // Creating a token. Store this token and provide this token 84 | // when ever you want to get data for which authentication is required 85 | const token: string = jwt.sign( 86 | { id: id, phone: phone }, 87 | process.env.TOKEN_SECRET_KEY!, 88 | { 89 | expiresIn: "1d", 90 | } 91 | ); 92 | 93 | // Returning 200 response and driver data after driver is created in DB 94 | res.status(200).json({ 95 | message: "Driver signed in successfully", 96 | driver: { 97 | id: id, 98 | name: name, 99 | phone: phone, 100 | email: email, 101 | image_url: imageUrl, 102 | active: active, 103 | vehicle_name: vehicleName, 104 | vehicle_number: vehicleNumber, 105 | }, 106 | token: token, 107 | }); 108 | } catch (error) { 109 | console.log(`Error in sign in: ${error}`); 110 | 111 | // Server error 112 | res.status(500).json({ 113 | error: { 114 | code: Err.code.SERVER_ERROR, 115 | message: Err.message.SERVER_ERROR, 116 | }, 117 | }); 118 | } 119 | }; 120 | 121 | export = driverSignIn; 122 | -------------------------------------------------------------------------------- /controllers/driver_sign_up_controller.ts: -------------------------------------------------------------------------------- 1 | import * as bcrypt from "bcrypt"; 2 | import * as jwt from "jsonwebtoken"; 3 | import Constant from "../constants/constant"; 4 | import Err from "../constants/error"; 5 | import Driver from "../models/Driver"; 6 | import Validator from "../utils/validator"; 7 | 8 | const driverSignUp = async (req: any, res: any) => { 9 | try { 10 | // Generating a random id 11 | const name: string = req.body.name; 12 | const phone: string = req.body.phone; 13 | const password: string = req.body.password; 14 | const vehicleName: string = req.body.vehicle_name; 15 | const vehicleNumber: string = req.body.vehicle_number; 16 | 17 | // If name, phone, password, vehicle name or vehicle number 18 | // does not exist 19 | // then 400 response and error message and code 20 | // is returned. 21 | if ( 22 | name === undefined || 23 | phone === undefined || 24 | password === undefined || 25 | vehicleName == undefined || 26 | vehicleNumber === undefined 27 | ) { 28 | return res.status(400).json({ 29 | error: { 30 | code: Err.code.EMPTY_PARAM, 31 | message: Err.message.EMPTY_PARAM, 32 | }, 33 | }); 34 | } 35 | 36 | // Checking if name is valid 37 | if (!Validator.validateName(name)) { 38 | return res.status(400).json({ 39 | error: { 40 | code: Err.code.INVALID_NAME, 41 | message: Err.message.INVALID_NAME, 42 | }, 43 | }); 44 | } 45 | 46 | // Checking if phone is valid 47 | if (!Validator.validatePhone(phone)) { 48 | return res.status(400).json({ 49 | error: { 50 | code: Err.code.INVALID_PHONE, 51 | message: Err.message.INVALID_PHONE, 52 | }, 53 | }); 54 | } 55 | 56 | // Checking if password is valid 57 | if (!Validator.validatePassword(password)) { 58 | return res.status(400).json({ 59 | error: { 60 | code: Err.code.INVALID_PASSWORD, 61 | message: Err.message.INVALID_PASSWORD, 62 | }, 63 | }); 64 | } 65 | 66 | // Checkinf if vehicle name is valid 67 | if (!Validator.validateName(vehicleName)) { 68 | return res.status(400).json({ 69 | error: { 70 | code: Err.code.INVALID_VEHICLE_NAME, 71 | message: Err.message.INVALID_VEHICLE_NAME, 72 | }, 73 | }); 74 | } 75 | 76 | // Checkinf if vehicle number plate number is valid 77 | if (!Validator.validateVehicleNumber(vehicleNumber)) { 78 | return res.status(400).json({ 79 | error: { 80 | code: Err.code.INVALID_VEHICLE_NUMBER, 81 | message: Err.message.INVALID_VEHICLE_NUMBER, 82 | }, 83 | }); 84 | } 85 | 86 | // Find if there is already a driver with this phone 87 | const oldDriver = await Driver.findOne({ phone: phone }); 88 | 89 | // Returning phone already present error if driver with same phone 90 | // already present 91 | if (oldDriver) { 92 | return res.status(409).json({ 93 | error: { 94 | code: Err.code.PHONE_ALREADY_EXISTS, 95 | message: Err.message.PHONE_ALREADY_EXISTS, 96 | }, 97 | }); 98 | } 99 | 100 | // Hashing password 101 | const hashedPassword = await bcrypt.hash(password, Constant.saltRounds); 102 | 103 | // Creating a driver in MongoDB 104 | const driver = await Driver.create({ 105 | name: name, 106 | phone: phone, 107 | password: hashedPassword, 108 | vehicle_name: vehicleName, 109 | vehicle_number: vehicleNumber, 110 | }); 111 | 112 | // MongoDB object _id 113 | const id: string = driver._id.toString(); 114 | 115 | // Creating a token. Store this token and provide this token 116 | // when ever you want to get data for which authentication is required 117 | const token: string = jwt.sign( 118 | { id: id, phone: phone }, 119 | process.env.TOKEN_SECRET_KEY!, 120 | { 121 | expiresIn: "1d", 122 | } 123 | ); 124 | 125 | // Returning 200 response and driver data after driver is created in DB 126 | res.status(200).json({ 127 | message: "Signed up and created driver successfully", 128 | driver: { 129 | id: id, 130 | name: name, 131 | phone: phone, 132 | }, 133 | token: token, 134 | }); 135 | } catch (error) { 136 | console.log(`Error in sign up: ${error}`); 137 | 138 | // Server error 139 | res.status(500).json({ 140 | error: { 141 | code: Err.code.SERVER_ERROR, 142 | message: Err.message.SERVER_ERROR, 143 | }, 144 | }); 145 | } 146 | }; 147 | 148 | export = driverSignUp; 149 | -------------------------------------------------------------------------------- /controllers/find_ride_driver_controller.ts: -------------------------------------------------------------------------------- 1 | import * as bcrypt from "bcrypt"; 2 | import axios, { AxiosResponse } from "axios"; 3 | import Err from "../constants/error"; 4 | import Driver from "../models/Driver"; 5 | import Helper from "../utils/helper"; 6 | import Constant from "../constants/constant"; 7 | 8 | /// Finds a driver near the users location who is active. 9 | /// If no driver is available then a new driver is created 10 | /// and then the drive info is sent to the user. 11 | const findRideDriver = async (req: any, res: any) => { 12 | try { 13 | const latitude: number = req.body.latitude; 14 | const longitude: number = req.body.longitude; 15 | const mapApiKey: string = req.body.map_api_key; 16 | 17 | // If latitude, longitude and map api key 18 | // are not present in req body 19 | // then send a 400 response 20 | if (!latitude || !longitude || !mapApiKey) { 21 | return res.status(400).json({ 22 | error: { 23 | code: Err.code.EMPTY_PARAM, 24 | message: Err.message.EMPTY_PARAM, 25 | }, 26 | }); 27 | } 28 | 29 | const changeLatitude: boolean = Math.random() <= 0.5; 30 | const sign: number = Math.random() <= 0.5 ? 1 : -1; 31 | 32 | // Adding or Subtracting 2 km from user latitude if [changeLatitude] is [true] 33 | const pointLatitude: number = 34 | latitude + (changeLatitude ? sign * 0.018 : 0); // 0.018 degree is 2 km 35 | 36 | // Adding or Subtracting 2 km from user longitude if [changeLatitude] is [false] 37 | const pointLongitude: number = 38 | longitude + (!changeLatitude ? sign * 0.018 : 0); // 0.018 degree is 2 km 39 | 40 | // Get the route info from point to user location 41 | const response: AxiosResponse = await axios.get( 42 | `https://api.tomtom.com/routing/1/calculateRoute/${pointLatitude},${pointLongitude}:${latitude},${longitude}/json?key=${mapApiKey}` 43 | ); 44 | 45 | // Route points 46 | const points = response.data["routes"][0]["legs"][0]["points"]; 47 | const driverSourceLatLon = points[0]; 48 | const driverDestinationLatLon = points[points.length - 1]; 49 | 50 | const driverSourceLatitude: number = Number.parseFloat( 51 | driverSourceLatLon["latitude"] 52 | ); 53 | const driverSourceLongitude: number = Number.parseFloat( 54 | driverSourceLatLon["longitude"] 55 | ); 56 | 57 | const driverDestinationLatitude: number = Number.parseFloat( 58 | driverDestinationLatLon["latitude"] 59 | ); 60 | const driverDestinationLongitude: number = Number.parseFloat( 61 | driverDestinationLatLon["longitude"] 62 | ); 63 | 64 | // Find a driver who is active 65 | let driver = await Driver.findOne({ active: true }); 66 | 67 | // If no driver is active then create a new Driver 68 | if (!driver) { 69 | const index: number = Helper.getRandomInt(Constant.names.length); 70 | 71 | const name: string = Constant.names[index]; 72 | const phone: string = Helper.generatePhone(); 73 | const password: string = Date.now.toString(); 74 | const vehicleName: string = Constant.vehicleNames[index]; 75 | const vehicleNumber: string = Constant.vehicleNumbers[index]; 76 | 77 | // Hashing password 78 | const hashedPassword = await bcrypt.hash(password, Constant.saltRounds); 79 | 80 | // Creating a driver in MongoDB 81 | driver = await Driver.create({ 82 | name: name, 83 | phone: phone, 84 | password: hashedPassword, 85 | vehicle_name: vehicleName, 86 | vehicle_number: vehicleNumber, 87 | }); 88 | } 89 | 90 | // Getting a driver field without the _id and __v fields 91 | const driverWithIdField = Helper.getObjectWithIdInsteadOf_idAnd__v(driver); 92 | 93 | // Responding with a driver object and the source and destination 94 | // position of the driver 95 | res.json({ 96 | driver: driverWithIdField, 97 | source_position: { 98 | latitude: driverSourceLatitude, 99 | longitude: driverSourceLongitude, 100 | }, 101 | destination_position: { 102 | latitude: driverDestinationLatitude, 103 | longitude: driverDestinationLongitude, 104 | }, 105 | }); 106 | } catch (error) { 107 | console.log(`Error in createRideDriver: ${error}`); 108 | 109 | // Server error 110 | res.status(500).json({ 111 | error: { 112 | code: Err.code.SERVER_ERROR, 113 | message: Err.message.SERVER_ERROR, 114 | }, 115 | }); 116 | } 117 | }; 118 | 119 | export = findRideDriver; 120 | -------------------------------------------------------------------------------- /controllers/get_previous_rides_controller.ts: -------------------------------------------------------------------------------- 1 | import Err from "../constants/error"; 2 | import Ride from "../models/Ride"; 3 | import User from "../models/User"; 4 | import Driver from "../models/Driver"; 5 | import Address from "../models/Address"; 6 | import Helper from "../utils/helper"; 7 | 8 | /// Validates Bearer token then sends a response 9 | /// with all the previous rides of the user. 10 | /// If token is not valid, user id is not present, user 11 | /// is not present then returns a 400 response. Else 12 | /// returns a list of all the previous rides of the user. 13 | const getPreviousRidesOfUser = async (req: any, res: any) => { 14 | try { 15 | const userId = req.body.user_id; 16 | 17 | // If user id not present return a 400 response 18 | if (!userId) { 19 | return res.status(400).json({ 20 | error: { 21 | code: Err.code.EMPTY_PARAM, 22 | message: Err.message.EMPTY_PARAM, 23 | }, 24 | }); 25 | } 26 | 27 | const currentDateTime: Date = new Date(); 28 | 29 | // Finding a list of Rides ridden by the user then delete 30 | // the '__v' field and replace 31 | // the '_id' field to 'id' field. 32 | let allPreviousRidesByUser: any[] = ( 33 | await Ride.find({ 34 | user: userId, 35 | $or: [ 36 | { end_time: { $exists: false } }, 37 | { end_time: { $lt: currentDateTime } }, 38 | ], 39 | }) 40 | ).map((previousRide) => { 41 | return Helper.getObjectWithIdInsteadOf_idAnd__v(previousRide); 42 | }); 43 | 44 | // Getting user, driver, source address, destination address and 45 | // deleting the '__v' field and replacing the '_id' field to 'id'. 46 | for (let index = 0; index < allPreviousRidesByUser.length; index++) { 47 | const userId = allPreviousRidesByUser[index].user; 48 | const user = await User.findById(userId); 49 | const userWithIdField = Helper.getObjectWithIdInsteadOf_idAnd__v(user); 50 | allPreviousRidesByUser[index].user = userWithIdField; 51 | 52 | const driverId = allPreviousRidesByUser[index].driver; 53 | const driver = await Driver.findById(driverId); 54 | const driverWithIdField = 55 | Helper.getObjectWithIdInsteadOf_idAnd__v(driver); 56 | allPreviousRidesByUser[index].driver = driverWithIdField; 57 | 58 | const sourceAddressId = allPreviousRidesByUser[index].source_address; 59 | const sourceAddress = await Address.findById(sourceAddressId); 60 | const sourceAddressWithIdField = 61 | Helper.getObjectWithIdInsteadOf_idAnd__v(sourceAddress); 62 | allPreviousRidesByUser[index].source_address = sourceAddressWithIdField; 63 | 64 | const destinationAddressId = 65 | allPreviousRidesByUser[index].destination_address; 66 | const destinationAddress = await Address.findById(destinationAddressId); 67 | const destinationAddressWithIdField = 68 | Helper.getObjectWithIdInsteadOf_idAnd__v(destinationAddress); 69 | allPreviousRidesByUser[index].destination_address = 70 | destinationAddressWithIdField; 71 | } 72 | 73 | // Sending a 200 response with all the previous rides 74 | // destination address to the user. 75 | res.status(200).json({ 76 | message: "All previous rides of the user fetched successfully.", 77 | previous_rides: allPreviousRidesByUser, 78 | }); 79 | } catch (error) { 80 | console.log(`Error in getPreviousRidesOfUser: ${error}`); 81 | 82 | // Server error 83 | res.status(500).json({ 84 | error: { 85 | code: Err.code.SERVER_ERROR, 86 | message: Err.message.SERVER_ERROR, 87 | }, 88 | }); 89 | } 90 | }; 91 | 92 | export = getPreviousRidesOfUser; 93 | -------------------------------------------------------------------------------- /controllers/get_user_info_controller.ts: -------------------------------------------------------------------------------- 1 | import * as Redis from "redis"; 2 | import Err from "../constants/error"; 3 | import User from "../models/User"; 4 | import Helper from "../utils/helper"; 5 | 6 | /// Gets user info from Redis server if present else gets user info 7 | /// from MongoDB 8 | const getUserInfo = async (req: any, res: any) => { 9 | try { 10 | const id: string = req.body.id; 11 | 12 | // If no id i.e. user id is present then return a 400 13 | // response 14 | if (!id) { 15 | return res.status(400).json({ 16 | error: { 17 | code: Err.code.EMPTY_PARAM, 18 | message: Err.message.EMPTY_PARAM, 19 | }, 20 | }); 21 | } 22 | 23 | // Create a redis client 24 | const redisClient = Redis.createClient(); 25 | 26 | // Get user info from redis server 27 | const userInfo = await redisClient.get(id); 28 | 29 | // If user info present in redis server then return user info 30 | if (userInfo) { 31 | return res.json({ 32 | user: userInfo, 33 | }); 34 | } 35 | 36 | // Find user info in MongoDB by using user id 37 | const user = await User.findById(id); 38 | 39 | // If user not found in MongoDB then return a 400 response 40 | if (!user) { 41 | return res.status(400).json({ 42 | error: { 43 | code: Err.code.NO_USER_WITH_ID, 44 | message: Err.message.NO_USER_WITH_ID, 45 | }, 46 | }); 47 | } 48 | 49 | // Get user object without `_id` and `_v` 50 | const userWithout_idAnd_v = Helper.getObjectWithIdInsteadOf_idAnd__v(user); 51 | 52 | // Set the user info value to the key id for 3600 seconds 53 | await redisClient.setEx(id, 3600, JSON.stringify(userWithout_idAnd_v)); 54 | 55 | // Return the user info 56 | res.json({ 57 | user: userWithout_idAnd_v, 58 | }); 59 | } catch (error) { 60 | console.log(`Error in getUserInfo: ${error}`); 61 | 62 | // Server error 63 | res.status(500).json({ 64 | error: { 65 | code: Err.code.SERVER_ERROR, 66 | message: Err.message.SERVER_ERROR, 67 | }, 68 | }); 69 | } 70 | }; 71 | 72 | export = getUserInfo; 73 | -------------------------------------------------------------------------------- /controllers/sign_in_controller.ts: -------------------------------------------------------------------------------- 1 | import * as bcrypt from "bcrypt"; 2 | import * as jwt from "jsonwebtoken"; 3 | import Err from "../constants/error"; 4 | import User from "../models/User"; 5 | import Validator from "../utils/validator"; 6 | 7 | const signIn = async (req: any, res: any) => { 8 | try { 9 | const phone: string = req.body.phone; 10 | const password: string = req.body.password; 11 | 12 | // Checks if phone and password is present 13 | if (phone === undefined || password === undefined) { 14 | // If phone and password not present then return a 400 response 15 | return res.status(400).json({ 16 | error: { 17 | code: Err.code.EMPTY_PARAM, 18 | message: Err.message.EMPTY_PARAM, 19 | }, 20 | }); 21 | } 22 | 23 | // Checks if phone is valid 24 | if (!Validator.validatePhone(phone)) { 25 | // If phone is not valid return a 400 response 26 | return res.status(400).json({ 27 | error: { 28 | code: Err.code.INVALID_PHONE, 29 | message: Err.message.INVALID_PHONE, 30 | }, 31 | }); 32 | } 33 | 34 | // Checks if password is valid 35 | if (!Validator.validatePassword(password)) { 36 | // If password is not valid return a 400 response 37 | return res.status(400).json({ 38 | error: { 39 | code: Err.code.INVALID_PASSWORD, 40 | message: Err.message.INVALID_PASSWORD, 41 | }, 42 | }); 43 | } 44 | 45 | // Checking if a user with this phone is present in the DB 46 | const user = await User.findOne({ phone: phone }); 47 | 48 | // If user not present return a 400 response 49 | if (!user) { 50 | return res.status(400).json({ 51 | error: { 52 | code: Err.code.NO_USER_WITH_PHONE, 53 | message: Err.message.NO_USER_WITH_PHONE, 54 | }, 55 | }); 56 | } 57 | 58 | const id: string = user._id.toString() as string; 59 | const name: string = user.name as string; 60 | const encryptedPassword: string = user.password; 61 | const email: string | undefined = user.email; 62 | const imageUrl: string | undefined = user.image_url; 63 | 64 | // Compare password with encrypted password 65 | const passwordCorrect: boolean = await bcrypt.compare( 66 | password, 67 | encryptedPassword 68 | ); 69 | 70 | // If password not correct then return 400 response 71 | if (!passwordCorrect) { 72 | return res.status(400).json({ 73 | error: { 74 | code: Err.code.WRONG_PASSWORD, 75 | message: Err.message.WRONG_PASSWORD, 76 | }, 77 | }); 78 | } 79 | 80 | // Creating a token. Store this token and provide this token 81 | // when ever you want to get data for which authentication is required 82 | const token: string = jwt.sign( 83 | { id: id, phone: phone }, 84 | process.env.TOKEN_SECRET_KEY!, 85 | { 86 | expiresIn: process.env.TOKEN_EXPIRY_TIME, 87 | } 88 | ); 89 | 90 | // Returning 200 response and user data after user is created in DB 91 | res.status(200).json({ 92 | message: "User signed in successfully", 93 | user: { 94 | id: id, 95 | name: name, 96 | phone: phone, 97 | email: email, 98 | image_url: imageUrl, 99 | }, 100 | token: token, 101 | }); 102 | } catch (error) { 103 | console.log(`Error in sign in: ${error}`); 104 | 105 | // Server error 106 | res.status(500).json({ 107 | error: { 108 | code: Err.code.SERVER_ERROR, 109 | message: Err.message.SERVER_ERROR, 110 | }, 111 | }); 112 | } 113 | }; 114 | 115 | export = signIn; 116 | -------------------------------------------------------------------------------- /controllers/sign_up_controller.ts: -------------------------------------------------------------------------------- 1 | import * as bcrypt from "bcrypt"; 2 | import * as jwt from "jsonwebtoken"; 3 | import Constant from "../constants/constant"; 4 | import Err from "../constants/error"; 5 | import User from "../models/User"; 6 | import Validator from "../utils/validator"; 7 | 8 | const signUp = async (req: any, res: any) => { 9 | try { 10 | // Generating a random id 11 | const name: string = req.body.name; 12 | const phone: string = req.body.phone; 13 | const password: string = req.body.password; 14 | 15 | // If name, phone or password does not exist 16 | // then 400 response and error message and code 17 | // is returned. 18 | if (name === undefined || phone === undefined || password === undefined) { 19 | return res.status(400).json({ 20 | error: { 21 | code: Err.code.EMPTY_PARAM, 22 | message: Err.message.EMPTY_PARAM, 23 | }, 24 | }); 25 | } 26 | 27 | // Checking if name is valid 28 | if (!Validator.validateName(name)) { 29 | return res.status(400).json({ 30 | error: { 31 | code: Err.code.INVALID_NAME, 32 | message: Err.message.INVALID_NAME, 33 | }, 34 | }); 35 | } 36 | 37 | // Checking if phone is valid 38 | if (!Validator.validatePhone(phone)) { 39 | return res.status(400).json({ 40 | error: { 41 | code: Err.code.INVALID_PHONE, 42 | message: Err.message.INVALID_PHONE, 43 | }, 44 | }); 45 | } 46 | 47 | // Checking if password is valid 48 | if (!Validator.validatePassword(password)) { 49 | return res.status(400).json({ 50 | error: { 51 | code: Err.code.INVALID_PASSWORD, 52 | message: Err.message.INVALID_PASSWORD, 53 | }, 54 | }); 55 | } 56 | 57 | // Find if there is already a user with this phone 58 | const oldUser = await User.findOne({ phone: phone }); 59 | 60 | // Returning phone already present error if user with same phone 61 | // already present 62 | if (oldUser) { 63 | return res.status(409).json({ 64 | error: { 65 | code: Err.code.PHONE_ALREADY_EXISTS, 66 | message: Err.message.PHONE_ALREADY_EXISTS, 67 | }, 68 | }); 69 | } 70 | 71 | // Hashing password 72 | const hashedPassword = await bcrypt.hash(password, Constant.saltRounds); 73 | 74 | // Creating a user in MongoDB 75 | const user = await User.create({ 76 | name: name, 77 | phone: phone, 78 | password: hashedPassword, 79 | }); 80 | 81 | // MongoDB object _id 82 | const id: string = user._id.toString(); 83 | 84 | // Creating a token. Store this token and provide this token 85 | // when ever you want to get data for which authentication is required 86 | const token: string = jwt.sign( 87 | { id: id, phone: phone }, 88 | process.env.TOKEN_SECRET_KEY!, 89 | { 90 | expiresIn: process.env.TOKEN_EXPIRY_TIME, 91 | } 92 | ); 93 | 94 | // Returning 200 response and user data after user is created in DB 95 | res.status(200).json({ 96 | message: "Signed up and created user successfully", 97 | user: { 98 | id: id, 99 | name: name, 100 | phone: phone, 101 | }, 102 | token: token, 103 | }); 104 | } catch (error) { 105 | console.log(`Error in sign up: ${error}`); 106 | 107 | // Server error 108 | res.status(500).json({ 109 | error: { 110 | code: Err.code.SERVER_ERROR, 111 | message: Err.message.SERVER_ERROR, 112 | }, 113 | }); 114 | } 115 | }; 116 | 117 | export = signUp; 118 | -------------------------------------------------------------------------------- /middlewares/token_middleware.ts: -------------------------------------------------------------------------------- 1 | import Err from "../constants/error"; 2 | import jwt from "jsonwebtoken"; 3 | 4 | /// Validates Bearer token from request. 5 | /// If token does not exist or is not in the correct format 6 | /// or is not valid 7 | /// a 400 response is sent and [undefined] is returned 8 | const validateBearerToken = (req: any, res: any, next?: Function): void => { 9 | const bearerToken: string = req.headers.authorization; 10 | 11 | // If there is no bearer token then sent 400 response 12 | if (!bearerToken) { 13 | res.status(400).json({ 14 | error: { 15 | code: Err.code.AUTHORIZATION_HEADER_MISSING, 16 | message: Err.message.AUTHORIZATION_HEADER_MISSING, 17 | }, 18 | }); 19 | 20 | throw `Token error: ${Err.message.AUTHORIZATION_HEADER_MISSING}`; 21 | } 22 | 23 | // Splitting the "Bearer "" in a Array as ["Bearer", ""] 24 | const arr: Array = bearerToken.split(" "); 25 | 26 | // If Bearer token format is not correct then send a 400 response 27 | if (arr.length < 2 || arr[0] !== "Bearer") { 28 | res.status(400).json({ 29 | error: { 30 | code: Err.code.INCORRECT_BEARER_TOKEN_FORMAT, 31 | message: Err.code.INCORRECT_BEARER_TOKEN_FORMAT, 32 | }, 33 | }); 34 | 35 | throw `Token error: ${Err.message.INCORRECT_BEARER_TOKEN_FORMAT}`; 36 | } 37 | 38 | // The in "Bearer " 39 | const token = arr[1]; 40 | 41 | // If token is not valid throw a 400 response 42 | jwt.verify(token, process.env.TOKEN_SECRET_KEY!, (error) => { 43 | if (error) { 44 | res.status(400).json({ 45 | error: { 46 | code: Err.code.INVALID_BEARER_TOKEN, 47 | message: Err.message.INVALID_BEARER_TOKEN, 48 | }, 49 | }); 50 | 51 | throw `Token error: ${Err.message.INVALID_BEARER_TOKEN}`; 52 | } 53 | }); 54 | 55 | if (next) { 56 | next(); 57 | } 58 | }; 59 | 60 | const tokenMiddleware = { validateBearerToken }; 61 | 62 | export = tokenMiddleware; 63 | -------------------------------------------------------------------------------- /models/Address.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from "mongoose"; 2 | 3 | const addressSchema = new mongoose.Schema({ 4 | place: { 5 | type: String, 6 | }, 7 | street: { 8 | type: String, 9 | default: "Unnamed Road", 10 | }, 11 | state: { 12 | type: String, 13 | }, 14 | country: { 15 | type: String, 16 | }, 17 | lat: { 18 | type: Number, 19 | required: true, 20 | }, 21 | lon: { 22 | type: Number, 23 | required: true, 24 | }, 25 | pincode: { 26 | type: String, 27 | }, 28 | }); 29 | 30 | const address = mongoose.model("Address", addressSchema, "addresses"); 31 | 32 | export = address; 33 | -------------------------------------------------------------------------------- /models/Driver.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from "mongoose"; 2 | import Validator from "../utils/validator"; 3 | 4 | const driverSchema = new mongoose.Schema({ 5 | name: { 6 | type: String, 7 | required: true, 8 | minLength: 1, 9 | maxLength: 1000, 10 | }, 11 | phone: { 12 | type: String, 13 | required: true, 14 | unique: true, 15 | minLength: 10, 16 | maxLength: 10, 17 | }, 18 | email: { 19 | type: String, 20 | unique: true, 21 | sparse: true, 22 | index: true, 23 | minLength: 5, 24 | maxLength: 254, 25 | validate: { 26 | validator: (email: string) => Validator.validateEmail(email), 27 | message: (props: any) => `${props.value} is not a valid email.`, 28 | }, 29 | }, 30 | password: { 31 | type: String, 32 | required: true, 33 | minLength: 8, 34 | maxLength: 1000, 35 | validate: { 36 | validator: (password: string) => Validator.validatePassword(password), 37 | message: (props: any) => `Password must be atleast 8 characters long.`, 38 | }, 39 | }, 40 | vehicle_name: { 41 | type: String, 42 | required: true, 43 | minLength: 1, 44 | maxLength: 1000, 45 | }, 46 | vehicle_number: { 47 | type: String, 48 | required: true, 49 | minLength: 1, 50 | maxLength: 1000, 51 | }, 52 | image_url: { 53 | type: String, 54 | minLength: 1, 55 | maxLength: 1000, 56 | }, 57 | active: { 58 | type: Boolean, 59 | default: true, 60 | }, 61 | }); 62 | 63 | const driver = mongoose.model("Driver", driverSchema, "drivers"); 64 | 65 | export = driver; 66 | -------------------------------------------------------------------------------- /models/Price.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from "mongoose"; 2 | 3 | const priceSchema = new mongoose.Schema({ 4 | base_price: { 5 | type: Number, 6 | required: true, 7 | }, 8 | price_per_km: { 9 | type: Number, 10 | required: true, 11 | }, 12 | }); 13 | 14 | const price = mongoose.model('Price', priceSchema, "prices") 15 | 16 | export = price; 17 | -------------------------------------------------------------------------------- /models/Review.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from "mongoose"; 2 | 3 | const reviewSchema = new mongoose.Schema({ 4 | review: { 5 | type: String, 6 | required: true, 7 | minLength: 1, 8 | maxLength: 50000, 9 | }, 10 | stars: { 11 | type: Number, 12 | required: true, 13 | minLength: 0, 14 | maxLength: 5, 15 | }, 16 | user: { 17 | type: mongoose.SchemaTypes.ObjectId, 18 | required: true, 19 | ref: "User", 20 | }, 21 | driver: { 22 | type: mongoose.SchemaTypes.ObjectId, 23 | required: true, 24 | ref: "Driver", 25 | }, 26 | createdAt: { 27 | type: Date, 28 | required: true, 29 | }, 30 | updatedAt: { 31 | type: Date, 32 | required: true, 33 | }, 34 | }); 35 | 36 | const review = mongoose.model("Review", reviewSchema, "reviews"); 37 | -------------------------------------------------------------------------------- /models/Ride.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from "mongoose"; 2 | 3 | const rideSchema = new mongoose.Schema({ 4 | user: { 5 | type: mongoose.SchemaTypes.ObjectId, 6 | required: true, 7 | ref: "User", 8 | }, 9 | driver: { 10 | type: mongoose.SchemaTypes.ObjectId, 11 | required: true, 12 | ref: "Driver", 13 | }, 14 | source_address: { 15 | type: mongoose.SchemaTypes.ObjectId, 16 | required: true, 17 | ref: "Address", 18 | }, 19 | destination_address: { 20 | type: mongoose.SchemaTypes.ObjectId, 21 | required: true, 22 | ref: "Address", 23 | }, 24 | start_time: { 25 | type: Date, 26 | required: true, 27 | }, 28 | end_time: { 29 | type: Date, 30 | }, 31 | cancelled: { 32 | type: Boolean, 33 | default: false, 34 | }, 35 | price: { 36 | type: Number, 37 | default: 0.0, 38 | }, 39 | discount_price: { 40 | type: Number, 41 | }, 42 | }); 43 | 44 | const ride = mongoose.model("Ride", rideSchema, "rides"); 45 | 46 | export = ride; 47 | -------------------------------------------------------------------------------- /models/User.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | import Validator from "../utils/validator"; 3 | 4 | const userSchema = new mongoose.Schema({ 5 | name: { 6 | type: String, 7 | required: true, 8 | minLength: 1, 9 | maxLength: 1000, 10 | }, 11 | phone: { 12 | type: String, 13 | required: true, 14 | unique: true, 15 | minLength: 10, 16 | maxLength: 10, 17 | validate: { 18 | validator: (phone: string) => Validator.validatePhone(phone), 19 | message: (props: any) => `${props.value} is not a valid phone.`, 20 | }, 21 | }, 22 | email: { 23 | type: String, 24 | unique: true, 25 | sparse: true, 26 | index: true, 27 | minLength: 5, 28 | maxLength: 254, 29 | validate: { 30 | validator: (email: string) => Validator.validateEmail(email), 31 | message: (props: any) => `${props.value} is not a valid email.`, 32 | }, 33 | }, 34 | password: { 35 | type: String, 36 | required: true, 37 | minLength: 8, 38 | maxLength: 1000, 39 | validate: { 40 | validator: (password: string) => Validator.validatePassword(password), 41 | message: (props: any) => `Password must be atleast 8 characters long.`, 42 | }, 43 | }, 44 | image_url: { 45 | type: String, 46 | minLength: 1, 47 | maxLength: 1000, 48 | }, 49 | }); 50 | 51 | const user = mongoose.model("User", userSchema, "users"); 52 | 53 | export = user; 54 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["./"], 3 | "ext": ".ts,.js", 4 | "ignore": [], 5 | "exec": "npx ts-node ./app.ts" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "safar_backend", 3 | "version": "1.0.0", 4 | "description": "Safar is a taxi booking application.", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node build/app.js", 9 | "dev": "nodemon build/app.js", 10 | "devTS": "npx nodemon" 11 | }, 12 | "author": "Dhritiman Roy", 13 | "license": "ISC", 14 | "dependencies": { 15 | "axios": "^1.4.0", 16 | "bcrypt": "^5.1.0", 17 | "dotenv": "^16.2.0", 18 | "express": "^4.18.2", 19 | "jsonwebtoken": "^9.0.0", 20 | "mongoose": "^7.3.0", 21 | "redis": "^4.6.7", 22 | "uuid": "^9.0.0" 23 | }, 24 | "devDependencies": { 25 | "@types/bcrypt": "^5.0.0", 26 | "@types/express": "^4.17.17", 27 | "@types/jsonwebtoken": "^9.0.2", 28 | "@types/mongoose": "^5.11.97", 29 | "@types/node": "^20.3.1", 30 | "@types/uuid": "^9.0.2", 31 | "nodemon": "^3.0.1", 32 | "ts-node": "^10.9.1", 33 | "typescript": "^5.1.3" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /routes/auth_router.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import signUp from "../controllers/sign_up_controller"; 3 | import driverSignUp from "../controllers/driver_sign_up_controller"; 4 | import signIn from "../controllers/sign_in_controller"; 5 | import driverSignIn from "../controllers/driver_sign_in_controller"; 6 | 7 | const router = express.Router(); 8 | 9 | router.post("/sign_up", signUp); 10 | 11 | router.post("/driver_sign_up", driverSignUp); 12 | 13 | router.post("/sign_in", signIn); 14 | 15 | router.post("/driver_sign_in", driverSignIn); 16 | 17 | export = router; 18 | -------------------------------------------------------------------------------- /routes/ride_router.ts: -------------------------------------------------------------------------------- 1 | import * as express from "express"; 2 | import getPreviousRidesOfUser from "../controllers/get_previous_rides_controller"; 3 | import addRideAndRideAddresses from "../controllers/add_ride_controller"; 4 | import tokenMiddleware from "../middlewares/token_middleware"; 5 | import getPriceInfoAndCalculateRidePrice from "../controllers/calculate_ride_price_controller"; 6 | import findRideDriver from "../controllers/find_ride_driver_controller"; 7 | 8 | const router = express.Router(); 9 | 10 | router.get( 11 | "/previous_rides", 12 | tokenMiddleware.validateBearerToken, 13 | getPreviousRidesOfUser 14 | ); 15 | 16 | router.post("/add_ride", tokenMiddleware.validateBearerToken, addRideAndRideAddresses); 17 | 18 | router.get( 19 | "/total_price", 20 | tokenMiddleware.validateBearerToken, 21 | getPriceInfoAndCalculateRidePrice 22 | ); 23 | 24 | router.get( 25 | "/find_ride_driver", 26 | tokenMiddleware.validateBearerToken, 27 | findRideDriver, 28 | ); 29 | 30 | export = router; 31 | -------------------------------------------------------------------------------- /routes/user_router.ts: -------------------------------------------------------------------------------- 1 | import * as express from "express"; 2 | import tokenMiddleware from "../middlewares/token_middleware"; 3 | import getUserInfo from "../controllers/get_user_info_controller"; 4 | 5 | const router = express.Router(); 6 | 7 | router.get("/", tokenMiddleware.validateBearerToken, getUserInfo); 8 | 9 | export = router; 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | "outDir": "./build", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /utils/helper.ts: -------------------------------------------------------------------------------- 1 | /// Helper functions present here. 2 | class Helper { 3 | /// This takes the object from the populate function and then 4 | /// deletes the '__v' field and 5 | /// changes the '_id' field to 'id' and returns a new 6 | /// object with the 'id' field. 7 | static getObjectWithIdInsteadOf_idAnd__v = (doc: any): Object => { 8 | const {_id, __v, ...rest } = doc.toObject(); 9 | rest.id = _id.toString(); 10 | return rest; 11 | } 12 | 13 | /// Gets a random int less than [max] 14 | static getRandomInt(max: number): number { 15 | return Math.floor(Math.random() * max); 16 | } 17 | 18 | /// Generates a 10 digit phone number 19 | static generatePhone(): string { 20 | let phone: string = ""; 21 | 22 | for (let index = 0; index < 10; index++) { 23 | phone += this.getRandomInt(10); 24 | } 25 | 26 | return phone; 27 | } 28 | } 29 | 30 | export = Helper; 31 | -------------------------------------------------------------------------------- /utils/validator.ts: -------------------------------------------------------------------------------- 1 | class Validator { 2 | // Email Regular Expressing 3 | private static emailRegex: RegExp = 4 | /^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/; 5 | 6 | /// Checks if name length is between 1 and 1000 7 | static validateName(name: string) { 8 | if (!name) { 9 | return false; 10 | } 11 | 12 | if (name.length < 0 || name.length > 1000) { 13 | return false; 14 | } 15 | 16 | return true; 17 | } 18 | 19 | /// Validates Email address 20 | static validateEmail(email: string) { 21 | // Checks if email is present or not 22 | if (!email) { 23 | return false; 24 | } 25 | 26 | // Checks if length of email is not more then 254 27 | if (email.length > 254) { 28 | return false; 29 | } 30 | 31 | // Checks if email matches the email RegExp 32 | const valid: boolean = this.emailRegex.test(email); 33 | if (!valid) { 34 | return false; 35 | } 36 | 37 | // Checks if part of email before '@' is not more then 64 38 | const emailParts: string[] = email.split("@"); 39 | if (emailParts[0].length > 64) { 40 | return false; 41 | } 42 | 43 | // Checks if each part of email after '@' which is separated by a '.' 44 | // is not more then 63 45 | const domainParts: string[] = emailParts[1].split("."); 46 | if ( 47 | domainParts.some((part: string) => { 48 | return part.length > 63; 49 | }) 50 | ) { 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | 57 | /// Checkinf if phone number length 10 and is numeric 58 | static validatePhone(phone: string) { 59 | if (!phone) { 60 | return false; 61 | } 62 | 63 | if (phone.length != 10) { 64 | return false; 65 | } 66 | 67 | return !isNaN(Number(phone)); 68 | } 69 | 70 | /// Validates if password length is between 8 and 1000 71 | static validatePassword(password: string) { 72 | if (!password) { 73 | return false; 74 | } 75 | 76 | return password.length >= 8; 77 | } 78 | 79 | /// Validates vehicle number plate number 80 | static validateVehicleNumber(vehicleNumber: string) { 81 | if (!vehicleNumber) { 82 | return false; 83 | } 84 | 85 | const numberPlateRegex: RegExp = 86 | /^[A-Z]{2}[0-9]{2}[A-HJ-NP-Z]{1,2}[0-9]{4}$/; 87 | return numberPlateRegex.test(vehicleNumber); 88 | } 89 | } 90 | 91 | export = Validator; 92 | --------------------------------------------------------------------------------