├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── .vscode └── launch.json ├── Dockerfile ├── LICENSE ├── README.md ├── api ├── index.js └── v1.0 │ ├── index.js │ └── modules │ ├── cron │ └── cron.js │ ├── paypal │ ├── controller.js │ ├── database │ │ ├── mongoDB │ │ │ ├── mongoDB.js │ │ │ └── schema.js │ │ └── mysql │ │ │ └── mysql.js │ ├── paypal.js │ └── routes.js │ └── user │ ├── controller.js │ ├── database │ ├── mongoDB │ │ ├── mongoDB.js │ │ └── schema.js │ └── mysql │ │ └── mysql.js │ ├── routes.js │ ├── testing │ ├── changePassword.js │ ├── forgotPassword.js │ ├── login.js │ ├── registration.js │ ├── resetPassword.js │ └── verifyEmail.js │ └── user.js ├── app.js ├── bin └── www ├── common ├── authentication.js ├── commondb.sql ├── database │ ├── mongoDB.js │ ├── mssql.js │ └── mysql.js ├── emailtemplate │ ├── auto_welcome.html │ ├── recharge.html │ ├── reset.html │ ├── ticket.html │ ├── ticketadmin.html │ └── welcome.html ├── error.js ├── functions.js ├── message.js ├── statusCode.js └── winston.js ├── config.js ├── package.json ├── public ├── profile │ ├── profile-1-1586792437622.png │ ├── profile-1586794147397.png │ └── profile-1586794403162.png └── stylesheets │ └── style.css ├── routes ├── index.js └── users.js ├── swagger.json └── views ├── error.handlebars ├── index.handlebars └── layouts └── main.handlebars /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | Dockerfile 4 | .dockerignore 5 | .git 6 | .gitignore -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | commonjs: true, 5 | es6: true 6 | }, 7 | extends: 'eslint:rended', 8 | globals: { 9 | Atomics: 'readonly', 10 | SharedArrayBuffer: 'readonly' 11 | }, 12 | parserOptions: { 13 | ecmaVersion: 2018 14 | }, 15 | rules: { 16 | indent: ['error', 2], 17 | 'linebreak-style': ['error', 'unix'], 18 | quotes: ['error', 'single'], 19 | semi: ['error', 'always'], 20 | 'no-console': 'off', 21 | 'no-undef': 'off' 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "semi": true, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "env": { "NODE_ENV": "DEV" }, 10 | "request": "launch", 11 | "name": "Launch Program", 12 | "skipFiles": ["/**"], 13 | "program": "${workspaceFolder}/bin/www" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app 3 | WORKDIR /home/node/app 4 | COPY package*.json ./ 5 | USER node 6 | RUN npm install 7 | COPY --chown=node:node . . 8 | EXPOSE 8080 9 | CMD [ "node", "bin/wwww" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Muddassar Shaikh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # commonAPI 2 | 3 | Common API is a project that can be used by each and every project as it has some common API like registration, login, verify email, forgot password, reset password change password, get user details, upload profile pic. 4 | 5 | Even Automated testing test are written using mocha, chai, supertest. 6 | 7 | POSTMAN Link for API -- https://www.getpostman.com/collections/f1b49d0f6d70e8574bc4 8 | -------------------------------------------------------------------------------- /api/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | router.use('/v1.0', require('./v1.0')); 5 | 6 | module.exports = router; -------------------------------------------------------------------------------- /api/v1.0/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | const userRouter = require('./modules/user/routes'); 5 | const paypalRouter = require('./modules/paypal/routes'); 6 | 7 | router.get('/', function (req, res, next) { 8 | res.send('Hello v1.0 GET API from Afoofa'); 9 | }); 10 | 11 | router.post('/', function (req, res, next) { 12 | res.send('Hello v1.0 POST API from Afoofa'); 13 | }); 14 | 15 | router.use('/user', userRouter); 16 | router.use('/paypal', paypalRouter); 17 | 18 | module.exports = router; 19 | -------------------------------------------------------------------------------- /api/v1.0/modules/cron/cron.js: -------------------------------------------------------------------------------- 1 | const con = require('../../../../common/database/mysql'); 2 | const util = require('util'); 3 | const query = util.promisify(con.query).bind(con); 4 | const CronJob = require('cron').CronJob; 5 | const { databaseName } = require('../../../../config'); 6 | const { errorHandler } = require('../../../../common/error'); 7 | 8 | /** 9 | * This cron job will run on every month on 1st at 12:00 am 10 | * It will delete all records from tables WHERE isDeleted=true 11 | */ 12 | new CronJob( 13 | '00 00 00 01 * *', 14 | async function () { 15 | try { 16 | const sqlSelectCall = ` 17 | SELECT DISTINCT TABLE_NAME 18 | FROM INFORMATION_SCHEMA.COLUMNS 19 | WHERE COLUMN_NAME IN ('isDeleted') 20 | AND TABLE_SCHEMA='afoofaDB'`; 21 | const getTables = await query(sqlSelectCall); 22 | console.log('getTables', getTables); 23 | if (getTables.length > 0) { 24 | const tablesInfo = []; 25 | for (let i = 0; i < getTables.length; i++) { 26 | tablesInfo.push(getTables[i].TABLE_NAME); 27 | } 28 | const tables = tablesInfo.join(','); 29 | const sqlDeleteCall = `DELETE FROM ${tables} WHERE isDeleted=1`; 30 | const deletedDetails = await query(sqlDeleteCall); 31 | console.log('getDetails', deletedDetails); 32 | } 33 | } catch (error) { 34 | errorHandler(error); 35 | } 36 | }, 37 | null, 38 | true 39 | ); 40 | -------------------------------------------------------------------------------- /api/v1.0/modules/paypal/controller.js: -------------------------------------------------------------------------------- 1 | const object = require('./paypal'); 2 | const functions = require('../../../../common/functions'); 3 | 4 | const controller = { 5 | getToken: async (req, res, next) => { 6 | try { 7 | const tokenDetails = await object.paypalService().getAccessToken(); 8 | res.send( 9 | functions.responseGenerator( 10 | tokenDetails.statusCode, 11 | tokenDetails.message, 12 | tokenDetails.data 13 | ) 14 | ); 15 | } catch (error) { 16 | return next(error); 17 | } 18 | }, 19 | 20 | webhookNotification: async (req, res, next) => { 21 | try { 22 | const tokenDetails = await object 23 | .paypalService() 24 | .webhookNotification(req.body); 25 | res.send( 26 | functions.responseGenerator( 27 | tokenDetails.statusCode, 28 | tokenDetails.message, 29 | tokenDetails.data 30 | ) 31 | ); 32 | } catch (error) { 33 | return next(error); 34 | } 35 | }, 36 | }; 37 | 38 | module.exports = controller; 39 | -------------------------------------------------------------------------------- /api/v1.0/modules/paypal/database/mongoDB/mongoDB.js: -------------------------------------------------------------------------------- 1 | const Paypal = require('./schema'); 2 | const { connection_failed } = require('../../../../../../common/statusCode'); 3 | 4 | class PaypalDatabase {} 5 | 6 | module.exports = { 7 | paypalDatabase: function () { 8 | return new PaypalDatabase(); 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /api/v1.0/modules/paypal/database/mongoDB/schema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const paypalSchema = mongoose.Schema( 4 | {}, 5 | { timestamps: true, collection: 'paypal' } 6 | ); 7 | 8 | const Paypal = mongoose.model('Paypal', paypalSchema); 9 | 10 | module.exports = Paypal; 11 | -------------------------------------------------------------------------------- /api/v1.0/modules/paypal/database/mysql/mysql.js: -------------------------------------------------------------------------------- 1 | const con = require('../../../../../../common/database/mysql'); 2 | const util = require('util'); 3 | const query = util.promisify(con.query).bind(con); 4 | const { databaseInitial } = require('../../../../../../config'); 5 | const { connection_failed } = require('../../../../../../common/statusCode'); 6 | 7 | class PaypalDatabase {} 8 | 9 | module.exports = { 10 | paypalDatabase: function () { 11 | return new PaypalDatabase(); 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /api/v1.0/modules/paypal/paypal.js: -------------------------------------------------------------------------------- 1 | // const functions = require('../../../../common/functions'); 2 | // const validator = require('validator'); 3 | // const db = require(`../user/database/${config.database}/${config.database}`); 4 | var request = require('request-promise'); 5 | const config = require('../../../../config'); 6 | const statusCode = require('../../../../common/statusCode'); 7 | const message = require('../../../../common/message'); 8 | const fs = require('fs'); 9 | 10 | class PaypalService { 11 | /** 12 | * API for get access token for paypal 13 | * @param {*} req (user detials) 14 | * @param {*} res (json with success/failure) 15 | */ 16 | async getAccessToken() { 17 | try { 18 | const auth = { 19 | username: config.paypalClientId, 20 | password: config.paypalSecret, 21 | }; 22 | 23 | const response = await request({ 24 | headers: { 25 | 'Content-Type': 'application/x-www-form-urlencoded', 26 | }, 27 | auth: auth, 28 | uri: `${config.paypalURL}/v1/oauth2/token`, 29 | method: 'POST', 30 | form: { grant_type: 'client_credentials' }, 31 | json: true, 32 | }); 33 | 34 | return { 35 | statusCode: statusCode.success, 36 | message: message.success, 37 | data: response, 38 | }; 39 | } catch (error) { 40 | return { 41 | statusCode: statusCode.bad_request, 42 | message: error.message, 43 | data: JSON.stringify(error), 44 | }; 45 | } 46 | } 47 | 48 | async webhookNotification(info) { 49 | try { 50 | var data = 51 | '\n=========================================================================================\n'; 52 | data += JSON.stringify(info); 53 | var filename = moment().format('DD-MM-YYYY'); 54 | await fs.appendFileSync( 55 | `${appRoot}/modules/thirdpartyapi/logs/${filename}.txt`, 56 | data 57 | ); 58 | 59 | if ( 60 | info.event_type == 'PAYMENT.SALE.COMPLETED' && 61 | info.resource.state == 'completed' 62 | ) { 63 | // info.create_time 64 | console.log(info); 65 | } 66 | } catch (error) { 67 | return { 68 | statusCode: statusCode.bad_request, 69 | message: error.message, 70 | data: JSON.stringify(error), 71 | }; 72 | } 73 | } 74 | } 75 | 76 | module.exports = { 77 | paypalService: function () { 78 | return new PaypalService(); 79 | }, 80 | }; 81 | -------------------------------------------------------------------------------- /api/v1.0/modules/paypal/routes.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | const api = require('./controller'); 3 | const auth = require('../../../../common/authentication'); 4 | 5 | // Middle layer for User API 6 | router.get('/token', auth.validateToken, api.getToken); 7 | router.post('/paypalWebhook', api.webhookNotification); 8 | module.exports = router; 9 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/controller.js: -------------------------------------------------------------------------------- 1 | const object = require('./user'); 2 | const functions = require('../../../../common/functions'); 3 | 4 | const controller = { 5 | //User Registration API 6 | registration: async (req, res, next) => { 7 | try { 8 | const registrationDetails = await object 9 | .userService() 10 | .registration(res.locals.requestedData); 11 | res.send( 12 | functions.responseGenerator( 13 | registrationDetails.statusCode, 14 | registrationDetails.message, 15 | registrationDetails.data 16 | ) 17 | ); 18 | } catch (error) { 19 | return next(error); 20 | } 21 | }, 22 | 23 | //Verify Email API 24 | verifyEmail: async (req, res, next) => { 25 | try { 26 | const verificationDetails = await object 27 | .userService() 28 | .verifyEmail(res.locals.requestedData); 29 | res.send( 30 | functions.responseGenerator( 31 | verificationDetails.statusCode, 32 | verificationDetails.message, 33 | verificationDetails.data 34 | ) 35 | ); 36 | } catch (error) { 37 | return next(error); 38 | } 39 | }, 40 | 41 | //Login API 42 | login: async (req, res, next) => { 43 | try { 44 | const loginDetails = await object 45 | .userService() 46 | .login(res.locals.requestedData); 47 | res.send( 48 | functions.responseGenerator( 49 | loginDetails.statusCode, 50 | loginDetails.message, 51 | loginDetails.data 52 | ) 53 | ); 54 | } catch (error) { 55 | return next(error); 56 | } 57 | }, 58 | 59 | // Change Password API 60 | changePassword: async (req, res, next) => { 61 | try { 62 | const changePasswordDetails = await object 63 | .userService() 64 | .changePassword( 65 | res.locals.tokenInfo.emailAddress, 66 | res.locals.requestedData 67 | ); 68 | res.send( 69 | functions.responseGenerator( 70 | changePasswordDetails.statusCode, 71 | changePasswordDetails.message, 72 | changePasswordDetails.data 73 | ) 74 | ); 75 | } catch (error) { 76 | return next(error); 77 | } 78 | }, 79 | 80 | // Forgot Password API 81 | forgotPassword: async (req, res, next) => { 82 | try { 83 | const forgotPasswordDetails = await object 84 | .userService() 85 | .forgotPassword(res.locals.requestedData); 86 | res.send( 87 | functions.responseGenerator( 88 | forgotPasswordDetails.statusCode, 89 | forgotPasswordDetails.message, 90 | forgotPasswordDetails.data 91 | ) 92 | ); 93 | } catch (error) { 94 | return next(error); 95 | } 96 | }, 97 | 98 | // Reset Password API 99 | resetPassword: async (req, res, next) => { 100 | try { 101 | const resetPasswordDetails = await object 102 | .userService() 103 | .resetPassword(res.locals.requestedData); 104 | res.send( 105 | functions.responseGenerator( 106 | resetPasswordDetails.statusCode, 107 | resetPasswordDetails.message, 108 | resetPasswordDetails.data 109 | ) 110 | ); 111 | } catch (error) { 112 | return next(error); 113 | } 114 | }, 115 | 116 | // Get Profile API 117 | getProfile: async (req, res, next) => { 118 | try { 119 | const userInformationDetails = await object 120 | .userService() 121 | .getProfile(res.locals.tokenInfo.emailAddress); 122 | res.send( 123 | functions.responseGenerator( 124 | userInformationDetails.statusCode, 125 | userInformationDetails.message, 126 | userInformationDetails.data 127 | ) 128 | ); 129 | } catch (error) { 130 | return next(error); 131 | } 132 | }, 133 | 134 | // Update Profile API 135 | updateProfile: async (req, res, next) => { 136 | try { 137 | const updateProfileDetails = await object 138 | .userService() 139 | .updateProfile( 140 | res.locals.tokenInfo.emailAddress, 141 | res.locals.requestedData 142 | ); 143 | res.send( 144 | functions.responseGenerator( 145 | updateProfileDetails.statusCode, 146 | updateProfileDetails.message, 147 | updateProfileDetails.data 148 | ) 149 | ); 150 | } catch (error) { 151 | return next(error); 152 | } 153 | }, 154 | 155 | // Add profile picture 156 | profilePic: async (req, res, next) => { 157 | try { 158 | const profilePicDetails = await object 159 | .userService() 160 | .addProfilePic( 161 | res.locals.tokenInfo.emailAddress, 162 | res.locals.requestedData 163 | ); 164 | res.send( 165 | functions.responseGenerator( 166 | profilePicDetails.statusCode, 167 | profilePicDetails.message, 168 | profilePicDetails.data 169 | ) 170 | ); 171 | } catch (error) { 172 | return next(error); 173 | } 174 | }, 175 | }; 176 | 177 | module.exports = controller; 178 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/database/mongoDB/mongoDB.js: -------------------------------------------------------------------------------- 1 | const User = require('./schema'); 2 | const { connection_failed } = require('../../../../../../common/statusCode'); 3 | 4 | class UserDatabase { 5 | /** 6 | * Database call to check if user exists 7 | * @param {*} req (email address & mobileNumber) 8 | * @param {*} res (json with success/failure) 9 | */ 10 | async checkIfuserExists(info) { 11 | try { 12 | const details = await User.find({ emailAddress: info.emailAddress }); 13 | return details; 14 | } catch (error) { 15 | throw { 16 | statusCode: connection_failed, 17 | message: error.message, 18 | data: JSON.stringify(error), 19 | }; 20 | } 21 | } 22 | 23 | /** 24 | * Database call for inserting user information 25 | * @param {*} req (user details) 26 | * @param {*} res (json with success/failure) 27 | */ 28 | async userRegistration(info) { 29 | const user = new User(info); 30 | try { 31 | const details = await user.save(); 32 | return details; 33 | } catch (error) { 34 | throw { 35 | statusCode: connection_failed, 36 | message: error.message, 37 | data: JSON.stringify(error), 38 | }; 39 | } 40 | } 41 | 42 | /** 43 | * Database call for updating the user email verification 44 | * @param {*} req (email address) 45 | * @param {*} res (json with success/failure) 46 | */ 47 | async verifyEmail(emailAddress) { 48 | try { 49 | const details = await User.updateOne( 50 | { emailAddress: emailAddress }, 51 | { isEmailVerified: 1 } 52 | ); 53 | return details; 54 | } catch (error) { 55 | throw { 56 | statusCode: connection_failed, 57 | message: error.message, 58 | data: JSON.stringify(error), 59 | }; 60 | } 61 | } 62 | 63 | /** 64 | * Database call for selecting user details for login 65 | * @param {*} req (emailAddress) 66 | * @param {*} res (json with success/failure) 67 | */ 68 | async getUser(emailAddress) { 69 | try { 70 | const details = await User.find( 71 | { emailAddress: emailAddress }, 72 | { 73 | fullName: 1, 74 | emailAddress: 1, 75 | userPassword: 1, 76 | mobileNumber: 1, 77 | isEmailVerified: 1, 78 | isActive: 1, 79 | isDeleted: 1, 80 | } 81 | ); 82 | return details; 83 | } catch (error) { 84 | throw { 85 | statusCode: connection_failed, 86 | message: error.message, 87 | data: JSON.stringify(error), 88 | }; 89 | } 90 | } 91 | 92 | /** 93 | * Database call for selecting userpassword for changing password 94 | * @param {*} req (emailAddress) 95 | * @param {*} res (json with success/failure) 96 | */ 97 | async getPassword(emailAddress) { 98 | try { 99 | const details = await User.find( 100 | { emailAddress: emailAddress }, 101 | { 102 | userPassword: 1, 103 | } 104 | ); 105 | return details; 106 | } catch (error) { 107 | throw { 108 | statusCode: connection_failed, 109 | message: error.message, 110 | data: JSON.stringify(error), 111 | }; 112 | } 113 | } 114 | 115 | /** 116 | * Database call for updating userpassword 117 | * @param {*} req (emailAddress) 118 | * @param {*} res (json with success/failure) 119 | */ 120 | async updateUserPassword(emailAddress, password) { 121 | try { 122 | const details = await User.updateOne( 123 | { emailAddress: emailAddress }, 124 | { userPassword: password } 125 | ); 126 | return details; 127 | } catch (error) { 128 | throw { 129 | statusCode: connection_failed, 130 | message: error.message, 131 | data: JSON.stringify(error), 132 | }; 133 | } 134 | } 135 | 136 | /** 137 | * Database call for updating userdetails 138 | * @param {*} req (emailAddress) 139 | * @param {*} res (json with success/failure) 140 | */ 141 | async updateUser(emailAddress, info) { 142 | try { 143 | const details = await User.updateOne( 144 | { emailAddress: emailAddress }, 145 | { fullName: info.fullName } 146 | ); 147 | return details; 148 | } catch (error) { 149 | throw { 150 | statusCode: connection_failed, 151 | message: error.message, 152 | data: JSON.stringify(error), 153 | }; 154 | } 155 | } 156 | 157 | /** 158 | * Database call for updating userdetails 159 | * @param {*} req (emailAddress) 160 | * @param {*} res (json with success/failure) 161 | */ 162 | async addProfilePic(emailAddress, path) { 163 | try { 164 | const details = await User.updateOne( 165 | { emailAddress: emailAddress }, 166 | { profileURL: path } 167 | ); 168 | return details; 169 | } catch (error) { 170 | throw { 171 | statusCode: connection_failed, 172 | message: error.message, 173 | data: JSON.stringify(error), 174 | }; 175 | } 176 | } 177 | } 178 | 179 | module.exports = { 180 | userDatabase: function () { 181 | return new UserDatabase(); 182 | }, 183 | }; 184 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/database/mongoDB/schema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const userSchema = mongoose.Schema( 4 | { 5 | fullName: { 6 | type: String, 7 | required: true, 8 | }, 9 | emailAddress: { 10 | type: String, 11 | required: true, 12 | unique: true, 13 | validate: { 14 | validator: (text) => { 15 | if (text !== null && text.length > 0) { 16 | const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 17 | return re.test(text); 18 | } 19 | return false; 20 | }, 21 | message: 'Invalid email address', 22 | }, 23 | }, 24 | userPassword: String, 25 | mobileNumber: String, 26 | isEmailVerified: { 27 | type: Number, 28 | default: 0, 29 | }, 30 | isActive: { 31 | type: Number, 32 | default: 1, 33 | }, 34 | isDeleted: { 35 | type: Number, 36 | default: 0, 37 | }, 38 | profileURL: String, 39 | }, 40 | { timestamps: true, collection: 'users' } 41 | ); 42 | 43 | const User = mongoose.model('User', userSchema); 44 | 45 | module.exports = User; 46 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/database/mysql/mysql.js: -------------------------------------------------------------------------------- 1 | const con = require('../../../../../../common/database/mysql'); 2 | const util = require('util'); 3 | const query = util.promisify(con.query).bind(con); 4 | const { databaseInitial } = require('../../../../../../config'); 5 | const { connection_failed } = require('../../../../../../common/statusCode'); 6 | 7 | class UserDatabase { 8 | /** 9 | * Database call to check if user exists 10 | * @param {*} req (email address & mobileNumber) 11 | * @param {*} res (json with success/failure) 12 | */ 13 | async checkIfuserExists(info) { 14 | try { 15 | const sqlSelectQuery = `SELECT * FROM ${databaseInitial}user WHERE emailAddress = ? OR mobileNumber = ?`; 16 | const details = await query(sqlSelectQuery, [ 17 | info.emailAddress, 18 | info.mobileNumber, 19 | ]); 20 | return details; 21 | } catch (error) { 22 | throw { 23 | statusCode: connection_failed, 24 | message: error.message, 25 | data: JSON.stringify(error), 26 | }; 27 | } 28 | } 29 | 30 | /** 31 | * Database call for inserting user information 32 | * @param {*} req (user details) 33 | * @param {*} res (json with success/failure) 34 | */ 35 | async userRegistration(info) { 36 | try { 37 | const sqlInsertQuery = `INSERT INTO ${databaseInitial}user(fullName, emailAddress, userPassword, mobileNumber) VALUES (?, ?, ?, ?)`; 38 | const details = await query(sqlInsertQuery, [ 39 | info.fullName, 40 | info.emailAddress, 41 | info.userPassword, 42 | info.mobileNumber, 43 | ]); 44 | return details; 45 | } catch (error) { 46 | throw { 47 | statusCode: connection_failed, 48 | message: error.message, 49 | data: JSON.stringify(error), 50 | }; 51 | } 52 | } 53 | 54 | /** 55 | * Database call for updating the user email verification 56 | * @param {*} req (email address) 57 | * @param {*} res (json with success/failure) 58 | */ 59 | async verifyEmail(emailAddress) { 60 | try { 61 | const sqlUpdateQuery = `UPDATE ${databaseInitial}user SET isEmailVerified = 1 WHERE emailAddress = ?`; 62 | const details = await query(sqlUpdateQuery, [emailAddress]); 63 | return details; 64 | } catch (error) { 65 | throw { 66 | statusCode: connection_failed, 67 | message: error.message, 68 | data: JSON.stringify(error), 69 | }; 70 | } 71 | } 72 | 73 | /** 74 | * Database call for selecting user details for login 75 | * @param {*} req (emailAddress) 76 | * @param {*} res (json with success/failure) 77 | */ 78 | async getUser(emailAddress) { 79 | try { 80 | const sqlSelectQuery = ` 81 | SELECT id, fullName, emailAddress, userPassword, mobileNumber, isEmailVerified, isActive, isDeleted 82 | FROM ${databaseInitial}user 83 | WHERE emailAddress = ?`; 84 | const details = await query(sqlSelectQuery, [emailAddress]); 85 | return details; 86 | } catch (error) { 87 | throw { 88 | statusCode: connection_failed, 89 | message: error.message, 90 | data: JSON.stringify(error), 91 | }; 92 | } 93 | } 94 | 95 | /** 96 | * Database call for selecting userpassword for changing password 97 | * @param {*} req (emailAddress) 98 | * @param {*} res (json with success/failure) 99 | */ 100 | async getPassword(emailAddress) { 101 | try { 102 | const sqlSelectQuery = `SELECT userPassword FROM ${databaseInitial}user WHERE emailAddress = ?`; 103 | const details = await query(sqlSelectQuery, [emailAddress]); 104 | return details; 105 | } catch (error) { 106 | throw { 107 | statusCode: connection_failed, 108 | message: error.message, 109 | data: JSON.stringify(error), 110 | }; 111 | } 112 | } 113 | 114 | /** 115 | * Database call for updating userpassword by email address 116 | * @param {*} req (emailAddress) 117 | * @param {*} res (json with success/failure) 118 | */ 119 | async updateUserPassword(emailAddress, password) { 120 | try { 121 | const sqlUpdateQuery = `UPDATE ${databaseInitial}user SET userPassword = ? WHERE emailAddress = ?`; 122 | const details = await query(sqlUpdateQuery, [password, emailAddress]); 123 | return details; 124 | } catch (error) { 125 | throw { 126 | statusCode: connection_failed, 127 | message: error.message, 128 | data: JSON.stringify(error), 129 | }; 130 | } 131 | } 132 | 133 | /** 134 | * Database call for updating userdetails 135 | * @param {*} req (emailAddress) 136 | * @param {*} res (json with success/failure) 137 | */ 138 | async updateUser(emailAddress, info) { 139 | try { 140 | const sqlUpdateQuery = `UPDATE ${databaseInitial}user SET fullName = ? WHERE emailAddress = ?`; 141 | const details = await query(sqlUpdateQuery, [ 142 | info.fullName, 143 | emailAddress, 144 | ]); 145 | return details; 146 | } catch (error) { 147 | throw { 148 | statusCode: connection_failed, 149 | message: error.message, 150 | data: JSON.stringify(error), 151 | }; 152 | } 153 | } 154 | 155 | /** 156 | * Database call for updating userdetails 157 | * @param {*} req (emailAddress) 158 | * @param {*} res (json with success/failure) 159 | */ 160 | async addProfilePic(emailAddress, path) { 161 | try { 162 | const sqlUpdateQuery = `UPDATE ${databaseInitial}user SET profileURL = ? WHERE emailAddress = ?`; 163 | const details = await query(sqlUpdateQuery, [path, emailAddress]); 164 | return details; 165 | } catch (error) { 166 | throw { 167 | statusCode: connection_failed, 168 | message: error.message, 169 | data: JSON.stringify(error), 170 | }; 171 | } 172 | } 173 | } 174 | 175 | module.exports = { 176 | userDatabase: function () { 177 | return new UserDatabase(); 178 | }, 179 | }; 180 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/routes.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | const api = require('./controller'); 3 | const auth = require('../../../../common/authentication'); 4 | 5 | // Middle layer for User API 6 | router.post('/registration', auth.decryptRequest, api.registration); 7 | router.post('/login', auth.decryptRequest, api.login); 8 | router.post('/verifyEmail', auth.decryptRequest, api.verifyEmail); 9 | router.post( 10 | '/changePassword', 11 | auth.validateToken, 12 | auth.decryptRequest, 13 | api.changePassword 14 | ); 15 | router.post('/forgotPassword', auth.decryptRequest, api.forgotPassword); 16 | router.post('/resetPassword', auth.decryptRequest, api.resetPassword); 17 | router.get('/profile', auth.validateToken, api.getProfile); 18 | router.put( 19 | '/profile', 20 | auth.validateToken, 21 | auth.decryptRequest, 22 | api.updateProfile 23 | ); 24 | router.put( 25 | '/profilePic', 26 | auth.validateToken, 27 | auth.decryptRequest, 28 | api.profilePic 29 | ); 30 | 31 | module.exports = router; 32 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/testing/changePassword.js: -------------------------------------------------------------------------------- 1 | const mocha = require('mocha'); 2 | const request = require('supertest'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const user = require('../user'); 6 | const app = require('../../../app'); 7 | const should = chai.should(); 8 | const message = require('../../common/message'); 9 | 10 | describe('User Module', () => { 11 | describe('"Change Password functionality"', () => { 12 | //Checking whether the functionality is being export 13 | it('should export a function', () => { 14 | expect(user.userService().verifyEmail).to.be.a('function'); 15 | }); 16 | 17 | it('should return a promise', () => { 18 | const checkPromise = user.userService().verifyEmail(); 19 | expect(checkPromise.then).to.be.a('function'); 20 | expect(checkPromise.catch).to.be.a('function'); 21 | }); 22 | 23 | it('should return a failure', async () => { 24 | const info = { 25 | oldPassword: '', 26 | newPassword: '', 27 | }; 28 | const changePassword = await user.userService().changePassword(1, info); 29 | console.log('Error: ', changePassword.message); 30 | if ( 31 | changePassword.message === message.badRequest || 32 | changePassword.message === message.invalidDetails || 33 | changePassword.message === message.invalidPassword 34 | ) { 35 | expect(changePassword.statusCode).to.be.equal('01'); 36 | } else { 37 | expect(changePassword.statusCode).to.be.equal('04'); 38 | } 39 | }); 40 | 41 | it('should return a success', async () => { 42 | const info = { 43 | oldPassword: '12345678', 44 | newPassword: '123456789', 45 | }; 46 | const changePassword = await user.userService().changePassword(1, info); 47 | console.log('Success: ', changePassword.message); 48 | expect(changePassword.statusCode).to.be.equal('00'); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/testing/forgotPassword.js: -------------------------------------------------------------------------------- 1 | const mocha = require('mocha'); 2 | const request = require('supertest'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const user = require('../user'); 6 | const app = require('../../../app'); 7 | const should = chai.should(); 8 | const message = require('../../common/message'); 9 | 10 | describe('User Module', () => { 11 | describe('"Forgot Password functionality"', () => { 12 | //Checking whether the functionality is being export 13 | it('should export a function', () => { 14 | expect(user.userService().forgotPassword).to.be.a('function'); 15 | }); 16 | 17 | it('should return a promise', () => { 18 | const checkPromise = user.userService().forgotPassword(); 19 | expect(checkPromise.then).to.be.a('function'); 20 | expect(checkPromise.catch).to.be.a('function'); 21 | }); 22 | 23 | it('should return a failure', async () => { 24 | const info = { 25 | emailAddress: '', 26 | }; 27 | const forgotPassword = await user.userService().forgotPassword(info); 28 | console.log('Error: ', forgotPassword.message); 29 | if (forgotPassword.message === message.invalidEmail) { 30 | expect(forgotPassword.statusCode).to.be.equal('01'); 31 | } else { 32 | expect(forgotPassword.statusCode).to.be.equal('04'); 33 | } 34 | }); 35 | 36 | it('should return a success', async () => { 37 | const info = { 38 | emailAddress: 'shaikh.muddassar8@gmail.com', 39 | }; 40 | const forgotPassword = await user.userService().forgotPassword(info); 41 | console.log('Success: ', forgotPassword.message); 42 | expect(forgotPassword.statusCode).to.be.equal('00'); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/testing/login.js: -------------------------------------------------------------------------------- 1 | const mocha = require('mocha'); 2 | const request = require('supertest'); 3 | const chai = require('chai'); 4 | const chaiHttp = require('chai-http'); 5 | const expect = chai.expect; 6 | const user = require('../user'); 7 | const app = require('../../../../../app'); 8 | const should = chai.should(); 9 | const message = require('../../../../../common/message'); 10 | chai.use(chaiHttp); 11 | 12 | describe('User Module', () => { 13 | describe('"login functionality"', () => { 14 | // Checking whether the functionality is being export 15 | it('should export a function', () => { 16 | expect(user.userService().login).to.be.a('function'); 17 | }); 18 | 19 | // Checking whether the functionality return promise 20 | it('should return a promise', () => { 21 | const checkPromiseResult = user.userService().login(); 22 | expect(checkPromiseResult.then).to.be.a('Function'); 23 | expect(checkPromiseResult.catch).to.be.a('Function'); 24 | }); 25 | 26 | it('should return a failure', async () => { 27 | const loginDetails = await user.userService().login({ 28 | emailAddress: 'shaikh.muddassar11@gmail.com', 29 | userPassword: '12345678', 30 | }); 31 | if ( 32 | loginDetails.message === message.invalidLoginDetails || 33 | loginDetails.message === message.accountDisable || 34 | loginDetails.message === message.emailVerify 35 | ) { 36 | expect(loginDetails.statusCode).to.be.equal('01'); 37 | } else { 38 | console.log(loginDetails.message); 39 | expect(loginDetails.statusCode).to.be.equal('04'); 40 | } 41 | }); 42 | 43 | it('should return a success if credential is valid', async () => { 44 | const loginDetails = await user.userService().login({ 45 | emailAddress: 'shaikh.muddassar8@gmail.com', 46 | userPassword: '123456789', 47 | }); 48 | expect(loginDetails.statusCode).to.be.equal('00'); 49 | }); 50 | 51 | it('should return success while calling from API', () => { 52 | return chai 53 | .request(app) 54 | .post('/api/user/login') 55 | .send({ 56 | emailAddress: 'shaikh.muddassar8@gmail.com', 57 | userPassword: '123456789', 58 | }) 59 | .then((res) => { 60 | expect(res.status).to.be.equal(200); 61 | expect(res.body.statusCode).to.be.equal('00'); 62 | }); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/testing/registration.js: -------------------------------------------------------------------------------- 1 | const mocha = require('mocha'); 2 | const request = require('supertest'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const user = require('../user'); 6 | const app = require('../../../app'); 7 | const should = chai.should(); 8 | const message = require('../../common/message'); 9 | 10 | describe('User Module', () => { 11 | describe('"Registration functionality"', () => { 12 | //Checking whether the functionality is being export 13 | it('should export a function', () => { 14 | expect(user.userService().registration).to.be.a('function'); 15 | }); 16 | 17 | it('should return a promise', () => { 18 | const checkPromise = user.userService().registration(); 19 | expect(checkPromise.then).to.be.a('function'); 20 | expect(checkPromise.catch).to.be.a('function'); 21 | }); 22 | 23 | it('should return a failure', async () => { 24 | const info = { 25 | fullName: 'Muddassar Shahanawaj Shaikh', 26 | emailAddress: 'shaikh', 27 | userPassword: '12345678', 28 | mobileNumber: '+918793786192', 29 | }; 30 | const registrationDetails = await user.userService().registration(info); 31 | console.log('Error: ', registrationDetails.message); 32 | if ( 33 | registrationDetails.message === message.invalidDetails || 34 | registrationDetails.message === message.duplicateDetails 35 | ) { 36 | expect(registrationDetails.statusCode).to.be.equal('01'); 37 | } else { 38 | expect(registrationDetails.statusCode).to.be.equal('04'); 39 | } 40 | }); 41 | 42 | it('Checking functionality with proper data', async () => { 43 | const info = { 44 | fullName: 'Muddassar Shahanawaj Shaikh', 45 | userPassword: '12345678', 46 | emailAddress: 'shaikh.muddassar8@gmail.com', 47 | mobileNumber: '+918793786192', 48 | }; 49 | const registrationDetails = await user.userService().registration(info); 50 | expect(registrationDetails.statusCode).to.be.equal('00'); 51 | expect(registrationDetails.data).to.be.a('object'); 52 | }); 53 | }); 54 | }); 55 | 56 | // Need to study 57 | // it('Should success if correct information is provided through API call', done => { 58 | // request(app) 59 | // .post('/api/user/registration') 60 | // .send({ 61 | // fullName: 'Muddassar Shahanawaj Shaikh', 62 | // userPassword: '12345678', 63 | // emailAddress: 'shaikh.muddassar8@gmail.com', 64 | // mobileNumber: '+918793786192' 65 | // }) 66 | // .end((err, res) => { 67 | // res.body.statusCode.should.be.equal('00'); 68 | // res.body.should.have.property('message'); 69 | // }); 70 | // done(); 71 | // }); 72 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/testing/resetPassword.js: -------------------------------------------------------------------------------- 1 | const mocha = require('mocha'); 2 | const request = require('supertest'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const user = require('../user'); 6 | const app = require('../../../app'); 7 | const should = chai.should(); 8 | const message = require('../../common/message'); 9 | 10 | describe('User Module', () => { 11 | describe('"Reset Password functionality"', () => { 12 | //Checking whether the functionality is being export 13 | it('should export a function', () => { 14 | expect(user.userService().resetPassword).to.be.a('function'); 15 | }); 16 | 17 | it('should return a promise', () => { 18 | const checkPromise = user.userService().resetPassword(); 19 | expect(checkPromise.then).to.be.a('function'); 20 | expect(checkPromise.catch).to.be.a('function'); 21 | }); 22 | 23 | it('should return a failure', async () => { 24 | const info = { 25 | emailAddress: 'sddsdfsdfasdfsdfasdfadsfadas', 26 | newPassword: '', 27 | }; 28 | const resetPassword = await user.userService().resetPassword(info); 29 | console.log('Error: ', resetPassword.message); 30 | if (resetPassword.message === message.invalidEmail) { 31 | expect(resetPassword.statusCode).to.be.equal('01'); 32 | } else { 33 | expect(resetPassword.statusCode).to.be.equal('04'); 34 | } 35 | }); 36 | 37 | // it('should return a success', async () => { 38 | // const info = { 39 | // emailAddress: 'shaikh.muddassar8@gmail.com' 40 | // }; 41 | // const forgotPassword = await user.userService().forgotPassword(info); 42 | // console.log('Success: ', forgotPassword.message); 43 | // expect(forgotPassword.statusCode).to.be.equal('00'); 44 | // }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/testing/verifyEmail.js: -------------------------------------------------------------------------------- 1 | const mocha = require('mocha'); 2 | const request = require('supertest'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const user = require('../user'); 6 | const app = require('../../../app'); 7 | const should = chai.should(); 8 | const message = require('../../common/message'); 9 | 10 | describe('User Module', () => { 11 | describe('"Verify Email functionality"', () => { 12 | //Checking whether the functionality is being export 13 | it('should export a function', () => { 14 | expect(user.userService().verifyEmail).to.be.a('function'); 15 | }); 16 | 17 | it('should return a promise', () => { 18 | const checkPromise = user.userService().verifyEmail(); 19 | expect(checkPromise.then).to.be.a('function'); 20 | expect(checkPromise.catch).to.be.a('function'); 21 | }); 22 | 23 | it('should return a failure', async () => { 24 | const info = { 25 | emailAddress: '', 26 | }; 27 | const verifyEmail = await user.userService().verifyEmail(info); 28 | console.log('Error: ', verifyEmail.message); 29 | if (verifyEmail.message === message.badRequest) { 30 | expect(verifyEmail.statusCode).to.be.equal('01'); 31 | } else { 32 | expect(verifyEmail.statusCode).to.be.equal('04'); 33 | } 34 | }); 35 | 36 | it('should return a success', async () => { 37 | const info = { 38 | emailAddress: 39 | '65794a68624763694f694a49557a49314e694973496e523563434936496b705856434a392e65794a6b59585268496a6f69633268686157746f4c6d31315a47526863334e68636a68415a32316861577775593239744969776961574630496a6f784e5459314d4441344d5467794c434a6c654841694f6a45314e6a55774f5451314f444a392e745f7275653749426338565f3061527277686f5241764c4b4b66756f37356d6d566a766f33577077744e6b', 40 | }; 41 | const verifyEmail = await user.userService().verifyEmail(info); 42 | console.log('Success: ', verifyEmail.message); 43 | expect(verifyEmail.statusCode).to.be.equal('00'); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /api/v1.0/modules/user/user.js: -------------------------------------------------------------------------------- 1 | const functions = require('../../../../common/functions'); 2 | const config = require('../../../../config'); 3 | const validator = require('validator'); 4 | const statusCode = require('../../../../common/statusCode'); 5 | const message = require('../../../../common/message'); 6 | const fs = require('fs'); 7 | const db = require(`./database/${config.database}/${config.database}`); 8 | 9 | class UserService { 10 | /** 11 | * API for user registration 12 | * @param {*} req (user detials) 13 | * @param {*} res (json with success/failure) 14 | */ 15 | async registration(info) { 16 | try { 17 | if ( 18 | !validator.isEmail(info.emailAddress) || 19 | validator.isEmpty(info.userPassword) || 20 | validator.isEmpty(info.fullName) || 21 | validator.isEmpty(info.mobileNumber) 22 | ) { 23 | throw { 24 | statusCode: statusCode.bad_request, 25 | message: message.badRequest, 26 | data: null, 27 | }; 28 | } 29 | 30 | const checkIfuserExists = await db.userDatabase().checkIfuserExists(info); 31 | 32 | if (checkIfuserExists.length > 0) { 33 | throw { 34 | statusCode: statusCode.bad_request, 35 | message: message.duplicateDetails, 36 | data: null, 37 | }; 38 | } 39 | 40 | info.userPassword = functions.encryptPassword(info.userPassword); 41 | 42 | const userRegistration = await db.userDatabase().userRegistration(info); 43 | 44 | let token = await functions.tokenEncrypt(info.emailAddress); 45 | token = Buffer.from(token, 'ascii').toString('hex'); 46 | let emailMessage = fs 47 | .readFileSync('./common/emailtemplate/welcome.html', 'utf8') 48 | .toString(); 49 | emailMessage = emailMessage 50 | .replace('$fullname', info.fullName) 51 | .replace('$link', config.emailVerificationLink + token); 52 | 53 | functions.sendEmail( 54 | info.emailAddress, 55 | message.registrationEmailSubject, 56 | emailMessage 57 | ); 58 | return { 59 | statusCode: statusCode.success, 60 | message: message.registration, 61 | data: userRegistration, 62 | }; 63 | } catch (error) { 64 | throw { 65 | statusCode: error.statusCode, 66 | message: error.message, 67 | data: JSON.stringify(error), 68 | }; 69 | } 70 | } 71 | 72 | /** 73 | * API for email verification 74 | * @param {*} req (email) 75 | * @param {*} res (json with success/failure) 76 | */ 77 | async verifyEmail(info) { 78 | try { 79 | if (!info.emailAddress) { 80 | throw { 81 | statusCode: statusCode.bad_request, 82 | message: message.badRequest, 83 | data: null, 84 | }; 85 | } 86 | const token = Buffer.from(info.emailAddress, 'hex').toString('ascii'); 87 | const tokenDecrypt = await functions.tokenDecrypt(token); 88 | if (tokenDecrypt.message === 'jwt expired') { 89 | throw { 90 | statusCode: statusCode.unauthorized, 91 | message: message.emailLinkExpired, 92 | data: null, 93 | }; 94 | } 95 | const verifyEmailDetails = await db 96 | .userDatabase() 97 | .verifyEmail(tokenDecrypt.data); 98 | return { 99 | statusCode: statusCode.success, 100 | message: message.emailVerificationSuccess, 101 | data: verifyEmailDetails, 102 | }; 103 | } catch (error) { 104 | throw { 105 | statusCode: error.statusCode, 106 | message: error.message, 107 | data: JSON.stringify(error), 108 | }; 109 | } 110 | } 111 | 112 | /** 113 | * API for user login 114 | * @param {*} req (email address & password) 115 | * @param {*} res (json with success/failure) 116 | */ 117 | async login(info) { 118 | try { 119 | if (!validator.isEmail(info.emailAddress)) { 120 | throw { 121 | statusCode: statusCode.bad_request, 122 | message: message.invalidLoginDetails, 123 | data: null, 124 | }; 125 | } 126 | 127 | const loginDetails = await db.userDatabase().getUser(info.emailAddress); 128 | 129 | if (loginDetails.length <= 0) { 130 | throw { 131 | statusCode: statusCode.bad_request, 132 | message: message.invalidLoginDetails, 133 | data: null, 134 | }; 135 | } 136 | const password = functions.decryptPassword(loginDetails[0].userPassword); 137 | if (password !== info.userPassword) { 138 | throw { 139 | statusCode: statusCode.bad_request, 140 | message: message.invalidLoginDetails, 141 | data: null, 142 | }; 143 | } 144 | 145 | if (loginDetails[0].isActive !== 1 || loginDetails[0].isDeleted !== 0) { 146 | throw { 147 | statusCode: statusCode.bad_request, 148 | message: message.accountDisable, 149 | data: null, 150 | }; 151 | } 152 | 153 | if (loginDetails[0].isEmailVerified === 0) { 154 | throw { 155 | statusCode: statusCode.bad_request, 156 | message: message.emailVerify, 157 | data: null, 158 | }; 159 | } 160 | 161 | const userDetails = { 162 | fullName: loginDetails[0].fullName, 163 | emailAddress: loginDetails[0].emailAddress, 164 | mobileNumber: loginDetails[0].mobileNumber, 165 | }; 166 | 167 | const token = await functions.tokenEncrypt(userDetails); 168 | 169 | userDetails.token = token; 170 | 171 | return { 172 | statusCode: statusCode.success, 173 | message: message.success, 174 | data: userDetails, 175 | }; 176 | } catch (error) { 177 | throw { 178 | statusCode: error.statusCode, 179 | message: error.message, 180 | data: JSON.stringify(error), 181 | }; 182 | } 183 | } 184 | 185 | /** 186 | * API to Change password 187 | * @param {*} req (old password, token, new password ) 188 | * @param {*} res (json with success/failure) 189 | */ 190 | async changePassword(emailAddress, info) { 191 | try { 192 | if ( 193 | validator.isEmpty(info.oldPassword) && 194 | validator.isEmpty(info.newPassword) 195 | ) { 196 | throw { 197 | statusCode: statusCode.bad_request, 198 | message: message.badRequest, 199 | data: null, 200 | }; 201 | } 202 | 203 | const getPassword = await db.userDatabase().getPassword(emailAddress); 204 | 205 | if (getPassword.length <= 0) { 206 | throw { 207 | statusCode: statusCode.bad_request, 208 | message: message.invalidDetails, 209 | data: null, 210 | }; 211 | } 212 | 213 | let password = functions.decryptPassword(getPassword[0].userPassword); 214 | if (password !== info.oldPassword) { 215 | throw { 216 | statusCode: statusCode.bad_request, 217 | message: message.invalidPassword, 218 | data: null, 219 | }; 220 | } 221 | 222 | // Encrypt password for the user 223 | password = functions.encryptPassword(info.newPassword); 224 | 225 | const updatePasswordDetails = await db 226 | .userDatabase() 227 | .updateUserPassword(emailAddress, password); 228 | 229 | return { 230 | statusCode: statusCode.success, 231 | message: message.passwordChanged, 232 | data: updatePasswordDetails, 233 | }; 234 | } catch (error) { 235 | throw { 236 | statusCode: error.statusCode, 237 | message: error.message, 238 | data: JSON.stringify(error), 239 | }; 240 | } 241 | } 242 | 243 | /** 244 | * API for Forgot Password 245 | * @param {*} req (email address ) 246 | * @param {*} res (json with success/failure) 247 | */ 248 | async forgotPassword(info) { 249 | try { 250 | if (!validator.isEmail(info.emailAddress)) { 251 | throw { 252 | statusCode: statusCode.bad_request, 253 | message: message.invalidEmail, 254 | data: null, 255 | }; 256 | } 257 | const userDetail = await db.userDatabase().getUser(info.emailAddress); 258 | 259 | if (userDetail.length <= 0) { 260 | throw { 261 | statusCode: statusCode.bad_request, 262 | message: message.invalidEmail, 263 | data: null, 264 | }; 265 | } 266 | const to = userDetail[0].emailAddress; 267 | let token = await functions.tokenEncrypt(to); 268 | token = Buffer.from(token, 'ascii').toString('hex'); 269 | const subject = message.forgotPasswordSubject; 270 | const link = config.resetPasswordLink + token; 271 | let emailMessage = fs 272 | .readFileSync('./common/emailtemplate/reset.html', 'utf8') 273 | .toString(); 274 | emailMessage = emailMessage 275 | .replace('$fullname', userDetail[0].fullName) 276 | .replace('$link', link) 277 | .replace('$emailId', config.supportEmail); 278 | 279 | functions.sendEmail(to, subject, emailMessage); 280 | return { 281 | statusCode: statusCode.success, 282 | message: message.resetLink, 283 | data: null, 284 | }; 285 | } catch (error) { 286 | throw { 287 | statusCode: error.statusCode, 288 | message: error.message, 289 | data: JSON.stringify(error), 290 | }; 291 | } 292 | } 293 | 294 | /** 295 | * API for Reset Password 296 | * @param {*} req (emailAddress ) 297 | * @param {*} res (json with success/failure) 298 | */ 299 | async resetPassword(info) { 300 | try { 301 | if ( 302 | validator.isEmpty(info.emailAddress) || 303 | validator.isEmpty(info.newPassword) 304 | ) { 305 | throw { 306 | statusCode: statusCode.bad_request, 307 | message: message.invalidDetails, 308 | data: null, 309 | }; 310 | } 311 | const emailAddress = Buffer.from(info.emailAddress, 'hex').toString( 312 | 'ascii' 313 | ); 314 | const emailAddressDetails = await functions.tokenDecrypt(emailAddress); 315 | if (!emailAddressDetails.data) { 316 | throw { 317 | statusCode: statusCode.unauthorized, 318 | message: message.emailLinkExpired, 319 | data: null, 320 | }; 321 | } 322 | const password = functions.encryptPassword(info.newPassword); 323 | 324 | const passwordDetails = await db 325 | .userDatabase() 326 | .updateUserPassword(emailAddressDetails.data, password); 327 | 328 | return { 329 | statusCode: statusCode.success, 330 | message: message.passwordReset, 331 | data: passwordDetails, 332 | }; 333 | } catch (error) { 334 | throw { 335 | statusCode: error.statusCode, 336 | message: error.message, 337 | data: JSON.stringify(error), 338 | }; 339 | } 340 | } 341 | 342 | /** 343 | * API for user history 344 | * @param {*} req (userId) 345 | * @param {*} res (json with success/failure) 346 | */ 347 | async getProfile(emailAdress) { 348 | try { 349 | const getProfileDetails = await db.userDatabase().getUser(emailAdress); 350 | if (getProfileDetails.length > 0) { 351 | const userDetails = { 352 | fullName: getProfileDetails[0].fullName, 353 | emailAddress: getProfileDetails[0].emailAddress, 354 | mobileNumber: getProfileDetails[0].mobileNumber, 355 | }; 356 | return { 357 | statusCode: statusCode.success, 358 | message: message.success, 359 | data: userDetails, 360 | }; 361 | } else { 362 | return { 363 | statusCode: statusCode.bad_request, 364 | message: message.noData, 365 | data: null, 366 | }; 367 | } 368 | } catch (error) { 369 | throw { 370 | statusCode: error.statusCode, 371 | message: error.message, 372 | data: JSON.stringify(error), 373 | }; 374 | } 375 | } 376 | 377 | /** 378 | * API to update profile 379 | * @param {*} req (token, user information ) 380 | * @param {*} res (json with success/failure) 381 | */ 382 | async updateProfile(userId, info) { 383 | try { 384 | if (validator.isEmpty(info.fullName)) { 385 | throw { 386 | statusCode: statusCode.bad_request, 387 | message: message.allFieldReq, 388 | data: null, 389 | }; 390 | } 391 | 392 | const userDetail = await db.userDatabase().updateUser(userId, info); 393 | 394 | return { 395 | statusCode: statusCode.success, 396 | message: message.profileUpdate, 397 | data: userDetail, 398 | }; 399 | } catch (error) { 400 | throw { 401 | statusCode: error.statusCode, 402 | message: error.message, 403 | data: JSON.stringify(error), 404 | }; 405 | } 406 | } 407 | 408 | /** 409 | * API for uploading user profile pic 410 | * @param {*} req (userId, base64 data) 411 | * @param {*} res (json with success/failure) 412 | */ 413 | async addProfilePic(emailAddress, info) { 414 | try { 415 | var imageType = info.imageInfo.name 416 | ? info.imageInfo.name.split('.')[1] 417 | : ''; 418 | if (!imageType) { 419 | throw { 420 | statusCode: statusCode.unsupported_media_type, 421 | message: message.invalidImage, 422 | data: [], 423 | }; 424 | } 425 | 426 | const imageName = `profile-${Date.now()}`; 427 | const path = 'profile/'; 428 | const imageInformation = { 429 | fileName: imageName, 430 | base64: info.imageInfo.base64, 431 | fileType: imageType, 432 | pathInfo: path, 433 | }; 434 | const imageURLInfo = await functions.uploadFile(imageInformation); 435 | 436 | const imageURL = path + imageURLInfo.fileName; 437 | 438 | const addProfilePic = await db 439 | .userDatabase() 440 | .addProfilePic(emailAddress, imageURL); 441 | return { 442 | statusCode: statusCode.success, 443 | message: message.success, 444 | data: addProfilePic, 445 | }; 446 | } catch (error) { 447 | throw { 448 | statusCode: error.statusCode, 449 | message: error.message, 450 | data: JSON.stringify(error), 451 | }; 452 | } 453 | } 454 | } 455 | 456 | module.exports = { 457 | userService: function () { 458 | return new UserService(); 459 | }, 460 | }; 461 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const createError = require('http-errors'); 2 | const express = require('express'); 3 | const path = require('path'); 4 | const cookieParser = require('cookie-parser'); 5 | const morgan = require('morgan'); 6 | const bodyParser = require('body-parser'); 7 | const cors = require('cors'); 8 | const app = express(); 9 | const db = require('./common/database/mongoDB'); 10 | const rateLimit = require('express-rate-limit'); 11 | const winston = require('./common/winston'); 12 | const { errorHandlerMiddleware, errorHandler } = require('./common/error'); 13 | const swaggerUi = require('swagger-ui-express'); 14 | const swaggerDocument = require('./swagger.json'); 15 | const cron = require('./api/v1.0/modules/cron/cron'); 16 | 17 | // view engine setup 18 | app.set('views', path.join(__dirname, 'views')); 19 | 20 | // HTTP request logger middleware for node.js 21 | app.use(morgan('combined', { stream: winston.stream })); 22 | 23 | /** 24 | * Parse incoming request bodies in a middleware before your handlers, 25 | * available under the req.body property. 26 | */ 27 | app.use(bodyParser.json()); 28 | app.use(bodyParser.urlencoded({ extended: false })); 29 | 30 | // Parse Cookie header and populate req.cookies 31 | app.use(cookieParser()); 32 | 33 | /** 34 | * CORS is a node.js package for providing a Connect/Express middleware 35 | * that can be used to enable CORS with various options. 36 | */ 37 | app.use(cors()); 38 | 39 | app.use(express.static(path.join(__dirname, 'public'))); 40 | 41 | /** 42 | * apply to all requests 43 | * Note - Rate Limiter can be applied to any individual API also. For more information 44 | * Please visit https://www.npmjs.com/package/express-rate-limit 45 | */ 46 | app.use( 47 | rateLimit({ 48 | windowMs: 15 * 60 * 1000, // 15 minutes 49 | max: 100, // limit each IP to 100 requests per windowMs 50 | }) 51 | ); 52 | 53 | // API Calling 54 | app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); 55 | app.use('/api', require('./api')); 56 | 57 | // catch 404 and forward to error handler 58 | app.use(function (req, res, next) { 59 | next(createError(404)); 60 | }); 61 | 62 | process.on('uncaughtException', function (err) { 63 | errorHandler(err); 64 | }); 65 | 66 | // error handler 67 | app.use(function (err, req, res, next) { 68 | errorHandlerMiddleware(err, req, res); 69 | }); 70 | 71 | module.exports = app; 72 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('e-shop:server'); 9 | var http = require('http'); 10 | const config = require('../config'); 11 | 12 | /** 13 | * Get port from environment and store in Express. 14 | */ 15 | 16 | var port = normalizePort(config.port || '6786'); 17 | app.set('port', port); 18 | 19 | /** 20 | * Create HTTP server. 21 | */ 22 | 23 | var server = http.createServer(app); 24 | 25 | /** 26 | * Listen on provided port, on all network interfaces. 27 | */ 28 | 29 | server.listen(port); 30 | server.on('error', onError); 31 | server.on('listening', onListening); 32 | 33 | /** 34 | * Normalize a port into a number, string, or false. 35 | */ 36 | 37 | function normalizePort(val) { 38 | var port = parseInt(val, 10); 39 | 40 | if (isNaN(port)) { 41 | // named pipe 42 | return val; 43 | } 44 | 45 | if (port >= 0) { 46 | // port number 47 | return port; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | /** 54 | * Event listener for HTTP server "error" event. 55 | */ 56 | 57 | function onError(error) { 58 | if (error.syscall !== 'listen') { 59 | throw error; 60 | } 61 | 62 | var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; 63 | 64 | // handle specific listen errors with friendly messages 65 | switch (error.code) { 66 | case 'EACCES': 67 | console.error(bind + ' requires elevated privileges'); 68 | process.exit(1); 69 | break; 70 | case 'EADDRINUSE': 71 | console.error(bind + ' is already in use'); 72 | process.exit(1); 73 | break; 74 | default: 75 | throw error; 76 | } 77 | } 78 | 79 | /** 80 | * Event listener for HTTP server "listening" event. 81 | */ 82 | 83 | function onListening() { 84 | var addr = server.address(); 85 | var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; 86 | debug('Listening on ' + bind); 87 | console.log('Listening on port:' + config.port); 88 | } 89 | -------------------------------------------------------------------------------- /common/authentication.js: -------------------------------------------------------------------------------- 1 | const functions = require('./functions'); 2 | const statusCode = require('./statusCode'); 3 | const message = require('./message'); 4 | 5 | const authenticationController = { 6 | validateToken: async (req, res, next) => { 7 | try { 8 | if (req.headers.auth) { 9 | const tokenDecryptInfo = await functions.tokenDecrypt(req.headers.auth); 10 | 11 | if (tokenDecryptInfo.data) { 12 | res.locals.tokenInfo = tokenDecryptInfo.data; 13 | const token = await functions.tokenEncrypt(tokenDecryptInfo.data); 14 | res.header('auth', token); 15 | next(); 16 | } else { 17 | throw { 18 | statusCode: statusCode.unauthorized, 19 | message: message.sessionExpire, 20 | data: null, 21 | }; 22 | } 23 | } else { 24 | throw { 25 | statusCode: statusCode.bad_request, 26 | message: message.tokenMissing, 27 | data: null, 28 | }; 29 | } 30 | } catch (error) { 31 | return next(error); 32 | } 33 | }, 34 | 35 | validateAdmin: (req, res, next) => { 36 | try { 37 | if (res.locals.tokenInfo.isAdmin === 1) { 38 | next(); 39 | } else { 40 | throw { 41 | statusCode: statusCode.unauthorized, 42 | message: message.unAuthorized, 43 | data: null, 44 | }; 45 | } 46 | } catch (error) { 47 | return next(error); 48 | } 49 | }, 50 | 51 | decryptRequest: (req, res, next) => { 52 | try { 53 | if (req.body) { 54 | const userinfo = functions.decryptData(req.body); 55 | res.locals.requestedData = userinfo; 56 | next(); 57 | } else { 58 | throw { 59 | statusCode: statusCode.bad_request, 60 | message: message.badRequest, 61 | data: null, 62 | }; 63 | } 64 | } catch (error) { 65 | return next(error); 66 | } 67 | }, 68 | }; 69 | 70 | module.exports = authenticationController; 71 | -------------------------------------------------------------------------------- /common/commondb.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE 2 | IF NOT EXISTS `commondb` /*!40100 DEFAULT CHARACTER SET utf8 */; 3 | USE `commondb`; 4 | -- MySQL dump 10.13 Distrib 5.7.29, for Linux (x86_64) 5 | -- 6 | -- Host: localhost Database: commondb 7 | -- ------------------------------------------------------ 8 | -- Server version 5.7.29-0ubuntu0.18.04.1 9 | 10 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 11 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 12 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 13 | /*!40101 SET NAMES utf8 */; 14 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 15 | /*!40103 SET TIME_ZONE='+00:00' */; 16 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 17 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 18 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 19 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 20 | 21 | -- 22 | -- Table structure for table `common_user` 23 | -- 24 | 25 | DROP TABLE IF EXISTS `common_user`; 26 | /*!40101 SET @saved_cs_client = @@character_set_client */; 27 | /*!40101 SET character_set_client = utf8 */; 28 | CREATE TABLE `common_user` 29 | ( 30 | `id` int 31 | (10) unsigned NOT NULL AUTO_INCREMENT, 32 | `fullName` varchar 33 | (200) CHARACTER 34 | SET utf8 DEFAULT 35 | NULL, 36 | `emailAddress` varchar 37 | (255) COLLATE utf8_unicode_ci NOT NULL, 38 | `mobileNumber` varchar 39 | (15) COLLATE utf8_unicode_ci NOT NULL, 40 | `userPassword` varchar 41 | (255) COLLATE utf8_unicode_ci NOT NULL, 42 | `isActive` int 43 | (2) DEFAULT '1', 44 | `profileURL` varchar 45 | (45) COLLATE utf8_unicode_ci DEFAULT NULL, 46 | `isEmailVerified` int 47 | (2) unsigned DEFAULT '0', 48 | `isDeleted` int 49 | (2) DEFAULT '0', 50 | `createdAt` datetime DEFAULT CURRENT_TIMESTAMP, 51 | `modifiedAt` datetime DEFAULT CURRENT_TIMESTAMP ON 52 | UPDATE CURRENT_TIMESTAMP, 53 | PRIMARY KEY 54 | (`id`), 55 | UNIQUE KEY `id_UNIQUE` 56 | (`id`), 57 | UNIQUE KEY `emailAddress_UNIQUE` 58 | (`emailAddress`), 59 | UNIQUE KEY `mobileNumber_UNIQUE` 60 | (`mobileNumber`) 61 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 62 | /*!40101 SET character_set_client = @saved_cs_client */; 63 | 64 | -- 65 | -- Dumping routines for database 'commondb' 66 | -- 67 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 68 | 69 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 70 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 71 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 72 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 73 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 74 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 75 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 76 | 77 | -- Dump completed on 2020-04-13 17:14:22 78 | -------------------------------------------------------------------------------- /common/database/mongoDB.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { mongoDBConnectionString } = require('../../config'); 3 | 4 | mongoose.connect(mongoDBConnectionString, { useNewUrlParser: true }); 5 | 6 | const db = mongoose.connection; 7 | // const db = mongoose.createConnection(mongoDBConnectionString); 8 | 9 | db.on('error', function (err) { 10 | console.log('Mongoose connection error: ' + err); 11 | }); 12 | 13 | db.on('connected', function () { 14 | console.log('Mongoose connected '); 15 | }); 16 | 17 | db.on('disconnected', function () { 18 | console.log('Mongoose disconnected'); 19 | }); 20 | 21 | //export the module 22 | module.exports = db; 23 | -------------------------------------------------------------------------------- /common/database/mssql.js: -------------------------------------------------------------------------------- 1 | const sql = require('mssql'); 2 | const config = require('../../config'); 3 | 4 | const connection = new sql.ConnectionPool({ 5 | user: config.databaseUser, 6 | password: config.databasePassword, 7 | server: config.databaseHost, 8 | database: config.databaseName, 9 | options: { 10 | encrypt: true, 11 | }, 12 | }); 13 | 14 | connection.connect(); 15 | 16 | var con = new sql.Request(connection); 17 | 18 | sql.connect(config, function (err) { 19 | if (err) { 20 | console.log('Error connecting to Database'); 21 | return; 22 | } 23 | console.log( 24 | 'Connection established to Host - [' + 25 | config.databaseHost + 26 | '] DB - [' + 27 | config.databaseName + 28 | ']' 29 | ); 30 | }); 31 | 32 | module.exports = con; 33 | -------------------------------------------------------------------------------- /common/database/mysql.js: -------------------------------------------------------------------------------- 1 | // MYSQL Database file 2 | 3 | const mysql = require('mysql'); 4 | const config = require('../../config'); 5 | 6 | const con = mysql.createPool({ 7 | connectionLimit: 10, 8 | host: config.databaseHost, 9 | user: config.databaseUser, 10 | password: config.databasePassword, 11 | database: config.databaseName, 12 | port: config.databasePort, 13 | }); 14 | 15 | con.getConnection(function (err, connection) { 16 | if (err) { 17 | console.log(err); 18 | console.log('Error connecting to Database'); 19 | return; 20 | } 21 | console.log('Connection established'); 22 | }); 23 | 24 | module.exports = con; 25 | -------------------------------------------------------------------------------- /common/emailtemplate/auto_welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 107 | 108 | 109 |
30 | 31 | 33 | 34 | 35 | 68 | 69 | 70 | 71 |
37 | 38 |
39 | 40 |

42 | Confirm your email address 43 |

44 |

46 | Hello $fullname,
Please click the button below to 47 | confirm your email address:

48 | email: $email
49 | password: $password 50 |

51 |
52 | Confirm 54 | Email 55 |
56 |

58 | Once confirmed, this email will be uniquely associated 59 | with your commonAPI account. 60 |

61 |

63 | Cheers,
64 | The commonAPI Team 65 |

66 |
67 |
72 | 73 | 106 |
110 | 111 | 112 | -------------------------------------------------------------------------------- /common/emailtemplate/recharge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Transaction Successfully Completed! 8 | 31 | 32 | 33 |
34 |

Hi there!

35 |
36 |

37 | You just made a successful payment.
38 | Your transaction id is $transactionId
39 | Your recharge details $product_desc
40 | thanks for transacting with us. We value your interest and aim to meet the expectations you deserve.
41 |

42 |
43 |
44 |

45 | Thank You,
46 | The FISH CMX Team 47 |

48 |
49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /common/emailtemplate/reset.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 98 | 99 | 100 |
30 | 31 | 33 | 34 | 35 | 62 | 63 | 64 | 65 |
37 | 38 |
39 | 40 |

42 | Password Reset Link 43 |

44 |

46 | Hello $fullname,
You have received this e-notification because of your recent request to 47 | Reset Your Password.
48 | In order to complete this request, please click the link below.
49 |

50 |
51 | Confirm 53 | Email 54 |
55 |

57 | Cheers,
58 | The commonAPI Team 59 |

60 |
61 |
66 | 67 | 97 |
101 | 102 | 103 | -------------------------------------------------------------------------------- /common/emailtemplate/ticket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Ticket Successfully generated! 8 | 31 | 32 | 33 |
34 |

Dear Valued FISH CMX Member,

35 |
36 |

37 | Thank you for contacting us about the problems,
38 | We’re glad to have the opportunity to review your concerns and a member of our team will contact you shortly to address any issues you might have.
39 |

40 |
41 |
42 |

43 | Thank You,
44 | The FISH CMX Team 45 |

46 |
47 | 48 | -------------------------------------------------------------------------------- /common/emailtemplate/ticketadmin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Ticket Successfully generated! 8 | 31 | 32 | 33 |
34 |

Hi Admin,

35 |
36 |

37 | FISH CMX User raised a concern related
38 | Name - $name
39 | Email Address - $emailId 40 | Subject - $subject
41 | Description - $description 42 |

43 |
44 |
45 |

46 | Thank You,
47 | The FISH CMX Team 48 |

49 |
50 | 51 | -------------------------------------------------------------------------------- /common/emailtemplate/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 102 | 103 | 104 |
30 | 31 | 33 | 34 | 35 | 66 | 67 | 68 | 69 |
37 | 38 |
39 | 40 |

42 | Confirm your email address 43 |

44 |

46 | Hello $fullname,
Please click the button below to 47 | confirm your email address: 48 |

49 |
50 | Confirm 52 | Email 53 |
54 |

56 | Once confirmed, this email will be uniquely associated 57 | with your commonAPI account. 58 |

59 |

61 | Cheers,
62 | The commonAPI Team 63 |

64 |
65 |
70 | 71 | 101 |
105 | 106 | 107 | -------------------------------------------------------------------------------- /common/error.js: -------------------------------------------------------------------------------- 1 | // const { responseGenerator } = require('./functions'); 2 | const winston = require('./winston'); 3 | 4 | const errorHandlerMiddleware = (error, req, res) => { 5 | winston.error( 6 | `${error.statusCode || 500} - ${error.message} - ${error.data} - ${ 7 | req.originalUrl 8 | } - ${req.method} - ${req.ip}` 9 | ); 10 | 11 | res.send( 12 | require('./functions').responseGenerator( 13 | error.statusCode, 14 | error.message, 15 | error.data 16 | ) 17 | ); 18 | }; 19 | 20 | function errorHandler(error) { 21 | winston.error(`${JSON.stringify(error)}`); 22 | } 23 | 24 | module.exports = { 25 | errorHandlerMiddleware, 26 | errorHandler, 27 | }; 28 | -------------------------------------------------------------------------------- /common/functions.js: -------------------------------------------------------------------------------- 1 | const config = require('../config'); 2 | const CryptoJS = require('crypto-js'); 3 | const jwt = require('jsonwebtoken'); 4 | const nodemailer = require('nodemailer'); 5 | const randomstring = require('randomstring'); 6 | const fs = require('fs'); 7 | const { errorHandler } = require('./error'); 8 | const AWS = require('aws-sdk'); 9 | 10 | /** 11 | * Function for Encrypting the data 12 | * @param {*} data (data to encrypt) 13 | * @param {*} return (encrypted data) 14 | */ 15 | function encryptData(data) { 16 | if (config.bodyEncryption) { 17 | var dataString = JSON.stringify(data); 18 | var response = CryptoJS.AES.encrypt(dataString, config.cryptokey); 19 | return { encResponse: response.toString() }; 20 | } 21 | return data; 22 | } 23 | 24 | /** 25 | * Function for decrypting the data 26 | * @param {*} data (data to decrypt) 27 | * @param {*} return (decrypt data) 28 | */ 29 | function decryptData(data) { 30 | if (config.bodyEncryption) { 31 | var decrypted = CryptoJS.AES.decrypt(data, config.cryptokey); 32 | if (decrypted) { 33 | var userinfo = JSON.parse(decrypted.toString(CryptoJS.enc.Utf8)); 34 | return userinfo; 35 | } else { 36 | return { userinfo: { error: 'Please send proper token' } }; 37 | } 38 | } 39 | return data; 40 | } 41 | 42 | /** 43 | * Function for Encrypting the password 44 | * @param {*} data (data to encrypt) 45 | * @param {*} return (encrypted data) 46 | */ 47 | function encryptPassword(data) { 48 | var response = CryptoJS.AES.encrypt(data, config.tokenkey); 49 | return response.toString(); 50 | } 51 | 52 | /** 53 | * Function for decrypting the password 54 | * @param {*} data (data to decrypt) 55 | * @param {*} return (decrypt data) 56 | */ 57 | function decryptPassword(data) { 58 | var decrypted = CryptoJS.AES.decrypt(data, config.tokenkey); 59 | if (decrypted) { 60 | var userinfo = decrypted.toString(CryptoJS.enc.Utf8); 61 | return userinfo; 62 | } else { 63 | return { userinfo: { error: 'Please send proper token' } }; 64 | } 65 | } 66 | 67 | /** 68 | * Function for encryting the userId with session 69 | * @param {*} data (data to encrypt) 70 | * @param {*} return (encrypted data) 71 | */ 72 | async function tokenEncrypt(data) { 73 | var token = await jwt.sign({ data: data }, config.tokenkey, { 74 | expiresIn: 24 * 60 * 60, 75 | }); // Expires in 1 day 76 | return token; 77 | } 78 | 79 | /** 80 | * Function for decryting the userId with session 81 | * @param {*} data (data to decrypt) 82 | * @param {*} return (decrypted data) 83 | */ 84 | async function tokenDecrypt(data) { 85 | try { 86 | const decode = await jwt.verify(data, config.tokenkey); 87 | return decode; 88 | } catch (error) { 89 | return error; 90 | } 91 | } 92 | 93 | /** 94 | * Function for creating response 95 | * @param {*} data (status, data, token) 96 | * @param {*} return (encrypted data) 97 | */ 98 | function responseGenerator(statusCode, message, data = '') { 99 | var details = { 100 | statusCode: statusCode, 101 | message: message, 102 | result: data, 103 | }; 104 | 105 | if (config.bodyEncryption) { 106 | return encryptData(details); 107 | } else { 108 | return details; 109 | } 110 | } 111 | 112 | /** 113 | * Function for sending email 114 | * @param {*} data (to, sub) 115 | * @param {*} return (decrypted data) 116 | */ 117 | async function sendEmail(to, subject, message) { 118 | var transporter = nodemailer.createTransport({ 119 | service: 'gmail', 120 | auth: { 121 | user: config.SMTPemailAddress, 122 | pass: config.SMTPPassword, 123 | }, 124 | }); 125 | 126 | var mailOptions = { 127 | from: 'developers.winjit@gmail.com', 128 | to: to, 129 | subject: subject, 130 | html: message, 131 | }; 132 | 133 | try { 134 | const smsDetails = await transporter.sendMail(mailOptions); 135 | return smsDetails; 136 | } catch (error) { 137 | errorHandler(error); 138 | } 139 | } 140 | 141 | /** 142 | * Function to randomly generate string 143 | * param 144 | * return (err, result) 145 | */ 146 | function generateRandomString(callback) { 147 | var referralCode = randomstring.generate({ 148 | length: 9, 149 | charset: 'alphanumeric', 150 | capitalization: 'uppercase', 151 | }); 152 | callback(referralCode); 153 | } 154 | 155 | /* 156 | Generate random string of specific size, 157 | which used for generating random password in create user by admin. 158 | */ 159 | function randomPasswordGenerater(length) { 160 | var result = ''; 161 | var characters = 162 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 163 | var charactersLength = characters.length; 164 | for (var i = 0; i < length; i++) { 165 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 166 | } 167 | return result; 168 | } 169 | 170 | /** 171 | * Function for Uploading file 172 | * @param {*} data (image information) 173 | * @param {*} return (uploaded information) 174 | */ 175 | async function uploadFile(fileInfo) { 176 | try { 177 | const fileType = fileInfo.fileType; 178 | const fileName = `${fileInfo.fileName}.${fileType}`; 179 | var base64 = fileInfo.base64.split(';base64,')[1]; 180 | var fileBuffer = new Buffer.from(base64, 'base64'); 181 | if (!fs.existsSync('./public/' + fileInfo.pathInfo)) { 182 | await fs.mkdirSync('./public/' + fileInfo.pathInfo, { recursive: true }); 183 | } 184 | await fs.writeFileSync( 185 | './public/' + fileInfo.pathInfo + fileName, 186 | fileBuffer, 187 | 'utf8' 188 | ); 189 | return { fileName: fileName }; 190 | } catch (e) { 191 | throw e; 192 | } 193 | } 194 | 195 | /** 196 | * Function for AWSs3Connection 197 | * @param {*} data (image information) 198 | * @param {*} return (uploaded information) 199 | */ 200 | const AWSs3Connection = new AWS.S3({ 201 | accessKeyId: config.awsAccessKey, 202 | secretAccessKey: config.awsSecretAccessKey, 203 | }); 204 | 205 | /** 206 | * Function for Uploading file to s3 bucket 207 | * @param {*} data (image information) 208 | * @param {*} return (uploaded information) 209 | */ 210 | async function s3FileUpload(postDataObj) { 211 | try { 212 | const fileType = postDataObj.fileType; 213 | const fileName = `${postDataObj.fileName}.${fileType}`; 214 | var base64 = postDataObj.base64.split(';base64,')[1]; 215 | var base64Data = new Buffer.from(base64, 'base64'); 216 | var contentType = 'application/octet-stream'; 217 | if (fileType == 'pdf') contentType = 'application/pdf'; 218 | if ( 219 | fileType == 'png' || 220 | fileType == 'jpg' || 221 | fileType == 'gif' || 222 | fileType == 'jpeg' || 223 | fileType == 'webp' || 224 | fileType == 'bmp' 225 | ) 226 | contentType = `image/${fileType}`; 227 | if (fileType == 'svg') contentType = 'image/svg+xml'; 228 | const params = { 229 | Bucket: `${config.awsBucket}/user-profile`, 230 | Key: `${postDataObj.key}.${fileType}`, 231 | Body: base64Data, 232 | ACL: 'public-read', 233 | ContentEncoding: 'base64', 234 | ContentType: contentType, 235 | }; 236 | const s3BucketFileLocation = await AWSs3Connection.upload(params).promise(); 237 | return { location: s3BucketFileLocation, fileName: imageName }; 238 | } catch (error) { 239 | throw error; 240 | } 241 | } 242 | 243 | /** 244 | * Function for deleting file from s3 bucket 245 | * @param {*} data (image information) 246 | * @param {*} return (uploaded information) 247 | */ 248 | async function s3RemoveFile(postDataObj) { 249 | try { 250 | const params = { 251 | Bucket: config.awsBucket, 252 | Delete: { 253 | Objects: [ 254 | { 255 | Key: `${postDataObj.key}`, 256 | }, 257 | ], 258 | Quiet: false, 259 | }, 260 | }; 261 | 262 | const s3BucketImageLocation = await AWSs3Connection.deleteObjects( 263 | params 264 | ).promise(); 265 | return s3BucketImageLocation; 266 | } catch (error) { 267 | throw error; 268 | } 269 | } 270 | 271 | module.exports = { 272 | encryptData, 273 | decryptData, 274 | encryptPassword, 275 | decryptPassword, 276 | tokenEncrypt, 277 | tokenDecrypt, 278 | responseGenerator, 279 | sendEmail, 280 | generateRandomString, 281 | randomPasswordGenerater, 282 | uploadFile, 283 | s3FileUpload, 284 | s3RemoveFile, 285 | }; 286 | -------------------------------------------------------------------------------- /common/message.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tokenIssue: 'Improper token', 3 | tokenMissing: 'Please send token', 4 | success: 'Success', 5 | movedPermanently: 'The requested URL has moved to a new URL', 6 | found: 'The requested URL has moved temporarily to a new URL', 7 | seeOthers: 'The requested URL can be found under a different URL', 8 | notModifies: 9 | 'The requested URL has not been modified since the specified date', 10 | temporaryRedirect: 'The requested URL has moved temporarily to a new URL', 11 | badRequest: 'Bad Request, request is made with invalid arguments', 12 | unAuthorized: 'Access token is missing or invalid', 13 | forbidden: 'Access to the requested URL is forbidden', 14 | notFound: 'The server can not find the requested URL', 15 | methodNotAllowed: 'The method specified in the request is not allowed', 16 | notAcceptable: 'Not Acceptable', 17 | preconditionFailed: 'Precondition Failed', 18 | unsupportedMediaType: 'Unsupported Media Type', 19 | internalServerError: 20 | 'The request was not completed. The server met an unexpected condition', 21 | notImplemented: 22 | 'The request was not completed. The server did not support the functionality required', 23 | connectionFailed: 24 | 'The request was not completed. The server is temporarily overloading or down', 25 | dbError: 'Unable to process your request, please try again', 26 | sessionExpire: 'Session expires. Please login again', 27 | invalidDetails: 'Invalid details', 28 | tryCatch: 'Something went wrong. Please contact admin.', 29 | registration: 'Registration done successfully', 30 | invalidEmail: 'Please insert email address in correct format', 31 | invalidLoginDetails: 'Invalid login details', 32 | duplicateDetails: 'Email Address or mobile number already exists', 33 | emailVerify: 'Please complete email verification process', 34 | emailVerificationSuccess: 35 | 'Email address successfully verified. Please login to continue', 36 | emailLinkExpired: 'Link has expired.', 37 | registrationEmailSubject: 'Welcome to CommonAPI', 38 | passwordChanged: 'Password changed successfully', 39 | invalidPassword: 'Password is not valid', 40 | forgotPasswordSubject: 'Common API, Forgot password link', 41 | resetLink: 42 | 'Reset link sent successfully. You will receive a link shortly if a user is registered.', 43 | passwordReset: 'Password has been successfully reset. Please login', 44 | profileUpdate: 'Profile updated successfully', 45 | allFieldReq: 'Please fill all required fields', 46 | noData: 'No information available', 47 | duplicateUser: 'User details already exist', 48 | accountDisable: 49 | 'Please contact admin. Your account has been deleted or blocked!', 50 | accountActivated: 'Account is activated', 51 | accountDeactivated: 'Account is deactivated', 52 | accountReactivated: 'Account is re-activated', 53 | sendingEmailFailed: 'Having some issue while sending email', 54 | invalidImage: 'Image type is not valid', 55 | }; 56 | -------------------------------------------------------------------------------- /common/statusCode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 1xx: Informational Communicates transfer protocol-level information. 3 | * 2xx: Success Indicates that the client’s request was accepted successfully. 4 | * 3xx: Redirection Indicates that the client must take some additional action in order to complete their request. 5 | * 4xx: Client Error This category of error status codes points the finger at clients. 6 | * 5xx: Server Error The server takes responsibility for these error status codes. 7 | */ 8 | 9 | module.exports = { 10 | success: 200, 11 | created: 201, 12 | accepted: 202, 13 | no_content: 204, 14 | moved_permanently: 301, 15 | found: 302, 16 | see_others: 303, 17 | not_modifies: 304, 18 | temporary_redirect: 307, 19 | bad_request: 400, 20 | unauthorized: 401, 21 | forbidden: 403, 22 | not_found: 404, 23 | method_not_allowed: 405, 24 | not_acceptable: 406, 25 | precondition_failed: 412, 26 | unsupported_media_type: 415, 27 | internal_server_error: 500, 28 | not_implemented: 501, 29 | connection_failed: 503, 30 | }; 31 | -------------------------------------------------------------------------------- /common/winston.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | 3 | // define the custom settings for each transport (file, console) 4 | const options = { 5 | file: { 6 | level: 'info', 7 | filename: `./app.log`, 8 | handleExceptions: true, 9 | json: true, 10 | maxsize: 5242880, // 5MB 11 | maxFiles: 5, 12 | colorize: false, 13 | }, 14 | console: { 15 | level: 'debug', 16 | handleExceptions: true, 17 | json: false, 18 | colorize: true, 19 | }, 20 | }; 21 | 22 | // instantiate a new Winston Logger with the settings defined above 23 | const logger = winston.createLogger({ 24 | transports: [ 25 | new winston.transports.File(options.file), 26 | new winston.transports.Console(options.console), 27 | ], 28 | exitOnError: false, // do not exit on handled exceptions 29 | }); 30 | 31 | // create a stream object with a 'write' function that will be used by `morgan` 32 | logger.stream = { 33 | write: function (message, encoding) { 34 | // use the 'info' log level so the output will be picked up by both transports (file and console) 35 | logger.info(message); 36 | }, 37 | }; 38 | 39 | module.exports = logger; 40 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | 3 | module.exports = { 4 | port: process.env[`${process.env.NODE_ENV}_PORT`], 5 | databaseHost: process.env[`${process.env.NODE_ENV}_DB_HOST`], 6 | databaseUser: process.env[`${process.env.NODE_ENV}_DB_USER`], 7 | databasePassword: process.env[`${process.env.NODE_ENV}_DB_PASSWORD`], 8 | databaseName: process.env[`${process.env.NODE_ENV}_DB_NAME`], 9 | databaseInitial: process.env[`${process.env.NODE_ENV}_DB_INITIAL`], 10 | database: process.env[`${process.env.NODE_ENV}_DB`], 11 | databasePort: process.env[`${process.env.NODE_ENV}_DB_PORT`], 12 | mongoDBConnectionString: 13 | process.env[`${process.env.NODE_ENV}_MONGO_DB_CONN_STRING`], 14 | emailVerificationLink: 15 | process.env[`${process.env.NODE_ENV}_EMAIL_VERIFICATION_LINK`], 16 | resetPasswordLink: process.env[`${process.env.NODE_ENV}_RESET_PASS_LINK`], 17 | tokenkey: process.env[`${process.env.NODE_ENV}_TOKEN_KEY`], 18 | bodyEncryption: false, 19 | supportEmail: process.env[`${process.env.NODE_ENV}_SUPPORT_EMAIL`], 20 | SMTPemailAddress: process.env[`${process.env.NODE_ENV}_SMTP_EMAILADDRESS`], 21 | SMTPPassword: process.env[`${process.env.NODE_ENV}_SMTP_PASS`], 22 | cryptokey: process.env[`${process.env.NODE_ENV_DB_PASS}_CRYPTO_KEY`], 23 | paypalURL: process.env[`${process.env.NODE_ENV}_PAYPAL_URL`], 24 | paypalClientId: process.env[`${process.env.NODE_ENV}_PAYPAL_CLIENTID`], 25 | paypalSecret: process.env[`${process.env.NODE_ENV}_PAYPAL_SECRET`], 26 | awsBucket: process.env[`${process.env.NODE_ENV}_AWS_BUCKET`], 27 | awsAccessKey: process.env[`${process.env.NODE_ENV}_AWS_ACCESS_KEY`], 28 | awsSecretAccessKey: 29 | process.env[`${process.env.NODE_ENV}_AWS_SECRET_ACCESS_KEY`], 30 | }; 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "common-api", 3 | "version": "2.0.0", 4 | "private": true, 5 | // For Linux 6 | "scripts": { 7 | "start": "NODE_ENV=DEV node ./bin/www", 8 | "start:testing": "NODE_ENV=TEST node ./bin/www", 9 | "start:production": "NODE_ENV=PROD node ./bin/www" 10 | }, 11 | // For running PM2 in linux 12 | "scripts": { 13 | "start": "NODE_ENV=DEV pm2 start ./bin/www", 14 | "start:testing": "NODE_ENV=TEST pm2 start ./bin/www", 15 | "start:production": "NODE_ENV=PROD pm2 start ./bin/www" 16 | }, 17 | // For Windows 18 | "scripts": { 19 | "start": "SET NODE_ENV=DEV& node ./bin/www", 20 | "start:testing": "SET NODE_ENV=TEST& node ./bin/www", 21 | "start:production": "SET NODE_ENV=PROD& node ./bin/www" 22 | }, 23 | // For running PM2 in Windows 24 | "scripts": { 25 | "start": "SET NODE_ENV=DEV& pm2 start ./bin/www", 26 | "start:testing": "SET NODE_ENV=TEST& pm2 start ./bin/www", 27 | "start:production": "SET NODE_ENV=PROD& pm2 start ./bin/www" 28 | }, 29 | "dependencies": { 30 | "aws-sdk": "^2.666.0", 31 | "cookie-parser": "~1.4.5", 32 | "cors": "^2.8.5", 33 | "cron": "^1.8.2", 34 | "crypto-js": "^4.0.0", 35 | "debug": "~4.1.1", 36 | "dotenv": "^8.2.0", 37 | "express": "~4.17.1", 38 | "express-rate-limit": "^5.1.3", 39 | "http-errors": "~1.7.3", 40 | "jsonwebtoken": "^8.5.1", 41 | "mongoose": "^5.9.10", 42 | "morgan": "~1.10.0", 43 | "mysql": "^2.18.1", 44 | "nodemailer": "^6.4.6", 45 | "randomstring": "^1.1.5", 46 | "request-promise": "^4.2.5", 47 | "swagger-ui-express": "^4.1.4", 48 | "validator": "^13.0.0", 49 | "winston": "^3.2.1" 50 | }, 51 | "devDependencies": { 52 | "chai": "^4.2.0", 53 | "chai-http": "^4.3.0", 54 | "mocha": "^7.1.2", 55 | "superagent": "^5.2.2", 56 | "supertest": "^4.0.2" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /public/profile/profile-1-1586792437622.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muddassarshaikh/commonAPI/487de393f5dbb591bc2319783e1827f2435c216a/public/profile/profile-1-1586792437622.png -------------------------------------------------------------------------------- /public/profile/profile-1586794147397.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muddassarshaikh/commonAPI/487de393f5dbb591bc2319783e1827f2435c216a/public/profile/profile-1586794147397.png -------------------------------------------------------------------------------- /public/profile/profile-1586794403162.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muddassarshaikh/commonAPI/487de393f5dbb591bc2319783e1827f2435c216a/public/profile/profile-1586794403162.png -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('index', { title: 'Common API' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /views/error.handlebars: -------------------------------------------------------------------------------- 1 |

{{message}}

2 |

{{error.status}}

3 |
{{error.stack}}
4 | -------------------------------------------------------------------------------- /views/index.handlebars: -------------------------------------------------------------------------------- 1 |

{{title}}

2 |

Welcome to {{title}}

3 | -------------------------------------------------------------------------------- /views/layouts/main.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{{body}}} 8 | 9 | --------------------------------------------------------------------------------