[
  {
    "path": "README.md",
    "content": "# nodejs-microservces-patterns\nnodejs-microservces-patterns\n\n- Simple Microservices Demo\n- Simple Auth and Autnz setup\n- CQRS Pattern\n- Event Driven Design Pattern \n\n### Different examples for understanding node js with microservoces Patterns \n\n####  https://www.youtube.com/watch?v=_pO0sDeQrp0&list=PLIGDNOJWiL182j1bD_nQm-SxARR5s977O&ab_channel=CodeLabs\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/.gitignore",
    "content": "node_modules\ndocs\n\nnode/node_modules\n.DS_Store\n\nnode/npm-debug.log\n.DS_Store\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/README.md",
    "content": "\n#What is this?\n\nThis porject/turotial explains how to implement a NodeJs Api Gateway, into a Microservices Architecture based on a Service Registry developed with a server-side discovery pattern.\n\n![ScreenShot](https://raw.github.com/alchimya/micro-node-api-gateway/master/Microservices_Architecture.png)\n\nActually, this project can be described as a complete Microservices Architecture containing four different microservices accessible via Api Gateway and discovered with a  Service Registry.\n\n#How to setup and configure\nTo <b>setup</b> the project, it is enough to launch the the bash script <b/>ServicesSetup.sh</b>\n<br/>\nThe <b>configuration</b> it is a bit tedious but it is very easy. In order you need to open all the <b>config.json</b> file that you will find in to each project folder (services and api-gateway) and setup the MondoDB configuration within the serviceRegistry object:\n\n```javascript\n  \"serviceRegistry\":{\n      \"watchDog\":{\n        \"isEnabled\":false,\n        \"timer\":30000\n      },\n      \"database\":{\n        \"name\":\"my_mongo_db\",\n        \"user\":\"my_mongo_db_user\",\n        \"password\":\"my_mongo_db_password\",\n        \"host\":\"my_mongo_db_host\",\n        \"port\":27017\n      }\n  }\n```\nA more dtailed description of the configuration is reported in to the section at the bottom of this document.\n\n#How to use\nTo start all services you must launch the bash script <b>ServicesStart.sh</b>. This script will provide to launch five differente clustered instances of a Node server as reported below:\n<br/>\n\nService         |Port \t     | Service Route | Api Gateway Ruote (8080)\n----------------|------------|---------------|-------------------------\nservice-login\t\t|\t8081\t     | /api/login\t   | /api/account/login   \nservice-signup  |\t8082\t     | /api/signup\t | /api/account/signup         \t      \nservice-orders\t|\t8084\t     | /api/orders\t | /api/crm/orders    \t      \nservice-log\t\t  |\t8084\t     | /api/log\t     |\t     ----- \napi-gateway\t\t  |\t8080\t     |   ----\t       |\t     ----- \n\n<br/>\nFor this tutorial, it is allowed to access directly (see Service Route) to the services, but, depending of your requirements, you can block this access, alllowing only the access via Api Gateway (see Api Gateway Ruote) that for this project is listening to the port 8080.\n\n#Api Gateway Configuraiton \nHere, a detailed description of the <b>config.json</b> file for the Pai Gateway\n```javascript\n{\n  \"server\":{\n    \"id\":\"MicroNodeApiGateway\",\n    \"port\":8080,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"login\", \"path\":\"api/account\", \"route\":\"account/login\"},\n      {\"name\":\"signup\", \"path\":\"api/account\", \"route\":\"account/signup\"},\n      {\"name\":\"orders\", \"path\":\"api/crm/orders\", \"route\":\"crm/orders\"}\n    ]\n  },\n  \"services\":[\n      {\"name\":\"ServiceLog\", \"endpointId\":\"log\"},\n      {\"name\":\"ServiceLogin\", \"endpointId\":\"login\"},\n      {\"name\":\"ServiceSignup\", \"endpointId\":\"signup\"},\n      {\"name\":\"ServiceOrders\", \"endpointId\":\"orders\"}\n  ],\n  \"serviceRegistry\":{\n      \"database\":{\n        \"name\":\"my_mongo_db\",\n        \"user\":\"my_mongo_db_user\",\n        \"password\":\"my_mongo_db_password\",\n        \"host\":\"my_mongo_db_host\",\n        \"port\":27017\n      }\n  }\n}\n```\nwhere:\n- server.id: it is a key to identify the microservice\n- server.port: it is the port where the microservice is listen to\n- server,isCluster: set true if you want you fork the main process depending of your CPU\n- server.https: enable/disable the https. It is needed to have the righ certificates to allow clients to connect under https\n- server.headers: put here all the response headers that you want to use, for example to enable the cross-origin resource sharing.\n\n- api.route: defines the main route of the api (e.g. /api)\n- api.modules: add in to this array all the module (js files for example Express middleware) that you want to use as api modules.\n- api.services: add in to this array all the services that you want to implement with your Api Gateway using as service name and entry poin id, the same values used to register a microservice in to the service registry (see below Microservice Configuration and for more detail take a look to this project https://github.com/alchimya/micro-node-service/edit/master/README.md).\n\n- serviceRegistry.watchDog: enable/disable the auto-update for the service registry. Speficy the update seconds into the timer property\n- serviceRegistry.databse: configure here your MongoDb connection params. This database represents your Service Registry\n\n\n\n#Microservice Configuraiton \nHere, a detailed description of the <b>config.json</b> file for a Microservice\n```javascript\n{\n  \"server\":{\n    \"id\":\"MicroNodeService\",\n    \"port\":8080,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"login\", \"route\":\"login\"}\n    ]\n  },\n  \"serviceRegistry\":{\n      \"watchDog\":{\n        \"isEnabled\":false,\n        \"timer\":30000\n      },\n      \"database\":{\n        \"name\":\"my_mongo_db\",\n        \"user\":\"my_mongo_db_user\",\n        \"password\":\"my_mongo_db_password\",\n        \"host\":\"my_mongo_db_host\",\n        \"port\":27017\n      }\n  }\n}\n```\nwhere:\n- server.id: it is a key to identify the microservice\n- server.port: it is the port where the microservice is listen to\n- server,isCluster: set true if you want you fork the main process depending of your CPU\n- server.https: enable/disable the https. It is needed to have the righ certificates to allow clients to connect under https\n- server.headers: put here all the response headers that you want to use, for example to enable the cross-origin resource sharing.\n\n- api.route: defines the main route of the api (e.g. /api)\n- api.modules: add in to this array all the module (js files for example Express middleware) that you want to use as api modules\n\n- serviceRegistry.watchDog: enable/disable the auto-update for the service registry. Speficy the update seconds into the timer property\n- serviceRegistry.databse: configure here your MongoDb connection params. This database represents your Service Registry\n\n\n![ScreenShot](https://raw.github.com/alchimya/micro-node-api-gateway/master/micro-node-api-gateway.gif)\n\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/ServicesSetup.sh",
    "content": "cd service-login\nsudo npm install\n\ncd ..\ncd service-orders\nsudo npm install\n\ncd ..\ncd service-signup\nsudo npm install\n\ncd ..\ncd service-log\nsudo npm install\n\ncd ..\ncd api-gateway\nsudo npm install"
  },
  {
    "path": "api-gateway-and-service-doscovery/ServicesStart.sh",
    "content": "cd service-login\nDEBUG=http node server &\n\ncd ..\ncd service-orders\nDEBUG=http node server &\n\ncd ..\ncd service-signup\nDEBUG=http node server &\n\ncd ..\ncd service-log\nDEBUG=http node server &\n\ncd ..\ncd api-gateway\nDEBUG=http node server"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/Dockerbuild.sh",
    "content": "docker build -t micro-node-service-api-gateway:latest .\nwinpty docker run -it --rm -p 8080:8080 --name micro-node-service-api-gateway micro-node-service-api-gateway:latest"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/Dockerfile",
    "content": "FROM node:6.2.0-onbuild\nEXPOSE 8080"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/api/account/login.js",
    "content": "/**\n * Created by domenicovacchiano on 10/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    apiGateway = require('../.././api-gateway');\n\nrouter.post('/', function (req, res,next) {\n    var request = new apiGateway();\n    request.sendRequest(\"ServiceLogin\",\"login\",req, res,next);\n});\n\nmodule.exports = router;"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/api/account/signup.js",
    "content": "/**\n * Created by domenicovacchiano on 10/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    apiGateway = require('../.././api-gateway');\n\nrouter.post('/', function (req, res,next) {\n    var request = new apiGateway();\n    request.sendRequest(\"ServiceSignup\",\"signup\",req, res,next);\n});\n\nmodule.exports = router;"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/api/crm/orders/orders.js",
    "content": "/**\n * Created by domenicovacchiano on 10/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    apiGateway = require('../../.././api-gateway');\n\nrouter.post('/', function (req, res,next) {\n    var request = new apiGateway();\n    request.sendRequest(\"ServiceOrders\",\"orders\",req, res,next);\n});\n\nmodule.exports = router;"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/api-gateway.js",
    "content": "/**\n * Created by domenicovacchiano on 10/07/16.\n */\n\nvar debug = require('debug')('http'),\n    config= require ('./config')(),\n    request = require('request'),\n    servicesHelper = require('./services-helper')(config.services),\n    serviceRegistry = require ('micro-node-service-registry-lib')({\n        name:config.serviceRegistry.database.name,\n        user:config.serviceRegistry.database.user,\n        password:config.serviceRegistry.database.password,\n        host:config.serviceRegistry.database.host,\n        port:config.serviceRegistry.database.port,\n        connectionPool:config.serviceRegistry.database.connectionPool\n    });\n\nvar ApiGateway = function () {\n    \n};\n\n\nApiGateway.prototype.sendRequest=function (serviceName,serviceEndpointId,req, res,next) {\n    \n    service=servicesHelper.getService(serviceName,serviceEndpointId);\n\n    serviceRegistry.find(service.name,service.endpointId,function (error,service) {\n        if (service && !error){\n            console.log(service);\n            request({\n                url: service.endpointUrl,\n                method: 'POST',\n                json:req.body\n            }, function(error, response, body){\n                if (error){\n                    return next(error)\n                }else {\n                    debug(body);\n                    return res.status(response.statusCode).send(body);\n                }\n            });\n        } else {\n            if (error){\n                return next(error);\n            }else {\n                return res.status(500).send(responseLib.errorResponse(1001,\"Service not found\",\"Application Error\"));\n            }\n\n        }\n    });\n};\n\nmodule.exports=ApiGateway;"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/config.js",
    "content": "/**\n * Created by domenicovacchiano on 25/05/16.\n */\n\nvar fs = require('fs');\n\nfunction Config() {\n    var config = JSON.parse(fs.readFileSync(__dirname  + '/config.json'), 'utf8');\n    return{\n        server:{\n            id:config.server.id,\n            port:config.server.port,\n            isCluster:config.server.isCluster,\n            https:config.server.https,\n            headers:config.server.headers,\n            httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname  + \"/\" + config.server.https.key) :null,\n            httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname  + \"/\" + config.server.https.ca) :null,\n        },\n        api:{\n            route:config.api.route,\n            modules:config.api.modules\n        },\n        services:config.services,\n        serviceRegistry:config.serviceRegistry\n    };\n\n}\nmodule.exports=Config;\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/config.json",
    "content": "{\n  \"server\":{\n    \"id\":\"MicroNodeApiGateway\",\n    \"port\":8080,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"login\", \"path\":\"api/account\", \"route\":\"account/login\"},\n      {\"name\":\"signup\", \"path\":\"api/account\", \"route\":\"account/signup\"},\n      {\"name\":\"orders\", \"path\":\"api/crm/orders\", \"route\":\"crm/orders\"}\n    ]\n  },\n  \"services\":[\n      {\"name\":\"ServiceLog\", \"endpointId\":\"log\"},\n      {\"name\":\"ServiceLogin\", \"endpointId\":\"login\"},\n      {\"name\":\"ServiceSignup\", \"endpointId\":\"signup\"},\n      {\"name\":\"ServiceOrders\", \"endpointId\":\"orders\"}\n  ],\n  \"serviceRegistry\":{\n      \"database\":{\n        \"name\":\"test\",\n        \"user\":\"\",\n        \"password\":\"\",\n        \"host\":\"192.168.29.43\",\n        \"port\":27017\n      }\n  }\n}\n\n\n\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/package.json",
    "content": "{\n  \"name\": \"DoorApiGateway\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Api Gateway\",\n  \"author\": {\n    \"name\": \"Domenico Vacchiano\",\n    \"email\": \"domenico@doorgames.com\",\n    \"url\": \"http://www.doorgames.com\"\n  },\n  \"homepage\": \"http://www.doorgames.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"\"\n  },\n  \"engines\": {\n    \"node\": \">= 0.6.0\",\n    \"npm\": \">= 1.0.0\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.13.4\",\n    \"body-parser\": \"^1.15.1\",\n    \"jsonwebtoken\": \"^7.0.0\",\n    \"request\": \"^2.72.0\",\n    \"morgan\": \"^1.7.0\",\n    \"micro-node-net-lib\": \"git@github.com:alchimya/micro-node-net-lib.git\",\n    \"micro-node-service-registry-lib\": \"git@github.com:alchimya/micro-node-service-registry-lib.git\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node server.js\"\n  },\n  \"main\": \"server.js\"\n}\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/server.js",
    "content": "/**\n * Created by domenicovacchiano on 10/07/16.\n */\n\nvar config= require ('./config')(),\n    express=require('express'),\n    debug = require('debug')('http'),\n    bodyParser = require('body-parser'),\n    morgan= require('morgan'),\n    cluster = require('cluster'),\n    numCPUs = require('os').cpus().length,\n    netLib = require ('micro-node-net-lib'),\n    apiGateway = require('./api-gateway'),\n    configServer= {\n        server:{\n            port:config.server.port\n        },\n        https:{\n            isEnabled:config.server.https.isEnabled,\n            key:config.server.httpsKeyContent,\n            ca:config.server.httpsCaContent\n        },\n        express:{\n            app:null\n        },\n        exitHandlers:[\"exit\",\"SIGINT\",\"SIGTERM\"]\n    },\n    server = netLib.server(configServer);\n\n    if (cluster.isMaster && config.server.isCluster) {\n        debug(\"cpus:\" + numCPUs);\n        for (var i = 0; i < numCPUs; i++) {\n            cluster.fork();\n        }\n        cluster.on('exit', function(worker, code, signal) {\n            console.log(\"cluster exit\");\n            debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);\n            cluster.fork();\n        });\n        \n    } else {\n\n        var app=express();\n        app.use(bodyParser.urlencoded({ extended: true }));\n        app.use(bodyParser.json());\n        app.use(morgan('dev'));\n        configServer.express.app = app;\n        \n        //header(s) setting\n        app.all('/*', function(req, res, next) {\n            config.server.headers.forEach(function(item) {\n                //console.log(item);\n                res.header(item.name, item.value);\n            });\n            next();\n        });\n\n        //pu here a middleware to check the api key\n        \n\n        //load API route(s)\n        config.api.modules.forEach(function(item) {\n            //console.log(item);\n            app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.path + \"/\" +  item.name));\n        });\n        \n        server.create(function (err,server) {\n            if (!err){\n                console.log(\"### \" + config.server.id + \" -> \" + (config.server.https ? \"HTTPS\" : \"HTTP\") + \" Server started on port \" +\n                    config.server.port + (config.server.isCluster ? \" cluster worker \" + cluster.worker.id : \"\"));\n            } else {\n                debug(err);\n            }\n        });\n        \n\n        //Http Error Handling on\n        app.use(function(err, req, res, next) {\n            debug(err);\n            var request = new apiGateway();\n            request.sendRequest(\"ServiceLog\",\"log\",req, res,next);\n            res.status(500).send({\n                code:1000,\n                message:\"Application Error\",\n                domain:\"Application Error\"\n            });\n        });\n    }"
  },
  {
    "path": "api-gateway-and-service-doscovery/api-gateway/services-helper.js",
    "content": "/**\n * Created by domenicovacchiano on 11/07/16.\n */\n\nfunction ServiceHelper(services) {\n    return{\n        getServiceWithName:function (serviceName) {\n            var service=services.filter(function( item ) {\n                return item.name == serviceName;\n            });\n            if (!service || !service[0] || service[0].length==0){\n                return null;\n            }\n            return service[0];\n        },\n        getService:function (serviceName,serviceEndpointId) {\n            var service=services.filter(function( item ) {\n                return (item.name == serviceName && item.endpointId == serviceEndpointId);\n            });\n            if (!service || !service[0] || service[0].length==0){\n                return null;\n            }\n            return service[0];\n        }\n    };\n};\n\nmodule.exports=ServiceHelper;"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/Dockerbuild.sh",
    "content": "docker build -t micro-node-service-log:latest .\nwinpty docker run -it --rm -p 8084:8084 --name micro-node-service-log micro-node-service-log:latest"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/Dockerfile",
    "content": "FROM node:6.2.0-onbuild\nEXPOSE 8084"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/config.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar fs = require('fs');\n\nfunction Config() {\n    var config = JSON.parse(fs.readFileSync(__dirname  + '/config.json'), 'utf8');\n    return{\n        server:{\n            id:config.server.id,\n            port:config.server.port,\n            isCluster:config.server.isCluster,\n            https:config.server.https,\n            headers:config.server.headers,\n            httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname  + \"/\" + config.server.https.key) :null,\n            httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname  + \"/\" + config.server.https.ca) :null,\n        },\n        api:{\n            route:config.api.route,\n            modules:config.api.modules\n        },\n        serviceRegistry:config.serviceRegistry\n        \n    };\n\n}\nmodule.exports=Config;\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/config.json",
    "content": "{\n  \"server\":{\n    \"id\":\"ServiceLog\",\n    \"port\":8084,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"log\", \"route\":\"log\"}\n    ]\n  },\n  \"serviceRegistry\":{\n      \"watchDog\":{\n        \"isEnabled\":false,\n        \"timer\":30000\n      },\n    \"database\":{\n      \"name\":\"my_mongo_db\",\n      \"user\":\"my_mongo_db_user\",\n      \"password\":\"my_mongo_db_password\",\n      \"host\":\"my_mongo_db_host\",\n      \"port\":27017\n    }\n  }\n}\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/log.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    debug = require('debug')('http'),\n    config= require ('./config')()\n\nrouter.post('/', function (req, res,next) {\n    return res.status(200).send(\"## Log -> This is just a test response ;-)\");\n});\n\nmodule.exports = router;"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/package.json",
    "content": "{\n  \"name\": \"MicroNodeService\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Micro Node Tutorial\",\n  \"author\": {\n    \"name\": \"Domenico Vacchiano\",\n    \"email\": \"info@domenicovacchiano.com\",\n    \"url\": \"http://www.domenicovacchiano.com\"\n  },\n  \"homepage\": \"http://www.domenicovacchiano.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"\"\n  },\n  \"engines\": {\n    \"node\": \">= 0.6.0\",\n    \"npm\": \">= 1.0.0\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.13.4\",\n    \"body-parser\": \"^1.15.1\",\n    \"request\": \"^2.72.0\",\n    \"morgan\": \"^1.7.0\",\n    \"network-address\": \"^1.1.0\",\n    \"micro-node-net-lib\": \"git@github.com:alchimya/micro-node-net-lib.git\",\n    \"micro-node-service-registry-lib\": \"git@github.com:alchimya/micro-node-service-registry-lib.git\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node server.js\"\n  },\n  \"main\": \"server.js\"\n}\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-log/server.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar config= require ('./config')(),\n    address = require('network-address'),\n    express=require('express'),\n    debug = require('debug')('http'),\n    bodyParser = require('body-parser'),\n    morgan= require('morgan'),\n    cluster = require('cluster'),\n    numCPUs = require('os').cpus().length,\n    netLib = require ('micro-node-net-lib'),\n    configServer= {\n        server:{\n            port:config.server.port\n        },\n        https:{\n            isEnabled:config.server.https.isEnabled,\n            key:config.server.httpsKeyContent,\n            ca:config.server.httpsCaContent\n        },\n        express:{\n            app:null\n        },\n        exitHandlers:[\"exit\",\"SIGINT\",\"SIGTERM\"]\n    }\n    server = netLib.server(configServer),\n    serviceRegistry = require ('micro-node-service-registry-lib')({\n        name:config.serviceRegistry.database.name,\n        user:config.serviceRegistry.database.user,\n        password:config.serviceRegistry.database.password,\n        host:config.serviceRegistry.database.host,\n        port:config.serviceRegistry.database.port,\n        connectionPool:config.serviceRegistry.database.connectionPool\n    });\n\n    if (cluster.isMaster && config.server.isCluster) {\n\n        debug(\"cpus:\" + numCPUs);\n        for (var i = 0; i < numCPUs; i++) {\n            cluster.fork();\n        }\n        cluster.on('exit', function(worker, code, signal) {\n            console.log(\"cluster exit\");\n            debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);\n            cluster.fork();\n        });\n\n    } else {\n        \n        var app=express();\n        app.use(bodyParser.urlencoded({ extended: true }));\n        app.use(bodyParser.json());\n        app.use(morgan('dev'));\n        configServer.express.app = app;\n        \n        //header(s) setting\n        app.all('/*', function(req, res, next) {\n            config.server.headers.forEach(function(item) {\n                //console.log(item);\n                res.header(item.name, item.value);\n            });\n            next();\n        });\n\n        //load API route(s)\n        config.api.modules.forEach(function(item) {\n            //console.log(item);\n            app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n        });\n        \n        server.create(function (err,server) {\n            if (!err){\n                //load API route(s) and register services\n                registerServer();\n                if (config.serviceRegistry.watchDog.isEnabled){\n                    setInterval(function(){\n                        registerServer();\n                    }, config.serviceRegistry.watchDog.timer);\n                }\n                console.log(\"### \" + config.server.id + \" -> \" + (config.server.https ? \"HTTPS\" : \"HTTP\") + \" Server started on port \" +\n                    config.server.port + (config.server.isCluster ? \" cluster worker \" + cluster.worker.id : \"\"));\n            } else {\n                debug(err);\n            }\n        });\n\n        server.registerExitHandler(function () {\n            unregisterServer();\n            debug(\"Server Exit Handled\");\n        });\n\n        var registerServer=function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"registerServer\");\n                config.api.modules.forEach(function(item) {\n                    //console.log(item);\n                    app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n                    serviceRegistry.register({\n                        serviceId:config.server.id,\n                        serviceHost:address(),\n                        servicePort:config.server.port,\n                        serviceProtocol:config.server.https.isEnabled ? \"https\" : \"http\",\n                        endpointId:item.name,\n                        endpointPath:config.api.route + \"/\" + item.route\n                    }, function (err,item) {\n                        if (err){\n                            console.log(app.next())\n                            debug(err);\n                        }\n                    });\n                });\n            }\n        };\n        var unregisterServer = function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"unregisterServer\");\n                config.api.modules.forEach(function(item) {\n                    serviceRegistry.unregister(config.server.id,item.name,function (err,item) {\n                        if (err){\n                            //TODO update flag inactive?\n                            console.log(err);\n                        }\n                        if (!config.server.isCluster){\n                            process.exit();\n                        }\n                    });\n                });\n            }\n        };\n  \n\n        \n    }\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/Dockerbuild.sh",
    "content": "docker build -t micro-node-service-login:latest .\nwinpty docker run -it --rm -p 8081:8081 --name micro-node-service-login micro-node-service-login:latest"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/Dockerfile",
    "content": "FROM node:6.2.0-onbuild\nEXPOSE 8081"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/config.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar fs = require('fs');\n\nfunction Config() {\n    var config = JSON.parse(fs.readFileSync(__dirname  + '/config.json'), 'utf8');\n    return{\n        server:{\n            id:config.server.id,\n            port:config.server.port,\n            isCluster:config.server.isCluster,\n            https:config.server.https,\n            headers:config.server.headers,\n            httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname  + \"/\" + config.server.https.key) :null,\n            httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname  + \"/\" + config.server.https.ca) :null,\n        },\n        api:{\n            route:config.api.route,\n            modules:config.api.modules\n        },\n        serviceRegistry:config.serviceRegistry\n        \n    };\n\n}\nmodule.exports=Config;\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/config.json",
    "content": "{\n  \"server\":{\n    \"id\":\"ServiceLogin\",\n    \"port\":8081,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"login\", \"route\":\"login\"}\n    ]\n  },\n  \"serviceRegistry\":{\n      \"watchDog\":{\n        \"isEnabled\":false,\n        \"timer\":30000\n      },\n    \"database\":{\n      \"name\":\"my_mongo_db\",\n      \"user\":\"my_mongo_db_user\",\n      \"password\":\"my_mongo_db_password\",\n      \"host\":\"my_mongo_db_host\",\n      \"port\":27017\n    }\n  }\n}\n\n\n\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/login.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    debug = require('debug')('http'),\n    config= require ('./config')()\n\nrouter.post('/', function (req, res,next) {\n    return res.status(200).send(\"## Login -> This is just a test response ;-)\");\n});\n\nmodule.exports = router;"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/package.json",
    "content": "{\n  \"name\": \"MicroNodeService\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Micro Node Tutorial\",\n  \"author\": {\n    \"name\": \"Domenico Vacchiano\",\n    \"email\": \"info@domenicovacchiano.com\",\n    \"url\": \"http://www.domenicovacchiano.com\"\n  },\n  \"homepage\": \"http://www.domenicovacchiano.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"\"\n  },\n  \"engines\": {\n    \"node\": \">= 0.6.0\",\n    \"npm\": \">= 1.0.0\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.13.4\",\n    \"body-parser\": \"^1.15.1\",\n    \"request\": \"^2.72.0\",\n    \"morgan\": \"^1.7.0\",\n    \"network-address\": \"^1.1.0\",\n    \"micro-node-net-lib\": \"git@github.com:alchimya/micro-node-net-lib.git\",\n    \"micro-node-service-registry-lib\": \"git@github.com:alchimya/micro-node-service-registry-lib.git\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node server.js\"\n  },\n  \"main\": \"server.js\"\n}\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-login/server.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar config= require ('./config')(),\n    address = require('network-address'),\n    express=require('express'),\n    debug = require('debug')('http'),\n    bodyParser = require('body-parser'),\n    morgan= require('morgan'),\n    cluster = require('cluster'),\n    numCPUs = require('os').cpus().length,\n    netLib = require ('micro-node-net-lib'),\n    configServer= {\n        server:{\n            port:config.server.port\n        },\n        https:{\n            isEnabled:config.server.https.isEnabled,\n            key:config.server.httpsKeyContent,\n            ca:config.server.httpsCaContent\n        },\n        express:{\n            app:null\n        },\n        exitHandlers:[\"exit\",\"SIGINT\",\"SIGTERM\"]\n    }\n    server = netLib.server(configServer),\n    serviceRegistry = require ('micro-node-service-registry-lib')({\n        name:config.serviceRegistry.database.name,\n        user:config.serviceRegistry.database.user,\n        password:config.serviceRegistry.database.password,\n        host:config.serviceRegistry.database.host,\n        port:config.serviceRegistry.database.port,\n        connectionPool:config.serviceRegistry.database.connectionPool\n    });\n\n    if (cluster.isMaster && config.server.isCluster) {\n\n        debug(\"cpus:\" + numCPUs);\n        for (var i = 0; i < numCPUs; i++) {\n            cluster.fork();\n        }\n        cluster.on('exit', function(worker, code, signal) {\n            console.log(\"cluster exit\");\n            debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);\n            cluster.fork();\n        });\n\n    } else {\n        \n        var app=express();\n        app.use(bodyParser.urlencoded({ extended: true }));\n        app.use(bodyParser.json());\n        app.use(morgan('dev'));\n        configServer.express.app = app;\n        \n        //header(s) setting\n        app.all('/*', function(req, res, next) {\n            config.server.headers.forEach(function(item) {\n                //console.log(item);\n                res.header(item.name, item.value);\n            });\n            next();\n        });\n\n        //load API route(s)\n        config.api.modules.forEach(function(item) {\n            //console.log(item);\n            app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n        });\n        \n        server.create(function (err,server) {\n            if (!err){\n                //load API route(s) and register services\n                registerServer();\n                if (config.serviceRegistry.watchDog.isEnabled){\n                    setInterval(function(){\n                        registerServer();\n                    }, config.serviceRegistry.watchDog.timer);\n                }\n                console.log(\"### \" + config.server.id + \" -> \" + (config.server.https ? \"HTTPS\" : \"HTTP\") + \" Server started on port \" +\n                    config.server.port + (config.server.isCluster ? \" cluster worker \" + cluster.worker.id : \"\"));\n            } else {\n                debug(err);\n            }\n        });\n\n        server.registerExitHandler(function () {\n            unregisterServer();\n            debug(\"Server Exit Handled\");\n        });\n\n        var registerServer=function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"registerServer\");\n                config.api.modules.forEach(function(item) {\n                    //console.log(item);\n                    app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n                    serviceRegistry.register({\n                        serviceId:config.server.id,\n                        serviceHost:address(),\n                        servicePort:config.server.port,\n                        serviceProtocol:config.server.https.isEnabled ? \"https\" : \"http\",\n                        endpointId:item.name,\n                        endpointPath:config.api.route + \"/\" + item.route\n                    }, function (err,item) {\n                        if (err){\n                            console.log(app.next())\n                            debug(err);\n                        }\n                    });\n                });\n            }\n        };\n        var unregisterServer = function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"unregisterServer\");\n                config.api.modules.forEach(function(item) {\n                    serviceRegistry.unregister(config.server.id,item.name,function (err,item) {\n                        if (err){\n                            //TODO update flag inactive?\n                            console.log(err);\n                        }\n                        if (!config.server.isCluster){\n                            process.exit();\n                        }\n                    });\n                });\n            }\n        };\n        \n        \n    }\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/Dockerbuild.sh",
    "content": "docker build -t micro-node-service-orders:latest .\nwinpty docker run -it --rm -p 8083:8083 --name micro-node-service-orders micro-node-service-orders:latest"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/Dockerfile",
    "content": "FROM node:6.2.0-onbuild\nEXPOSE 8083"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/config.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar fs = require('fs');\n\nfunction Config() {\n    var config = JSON.parse(fs.readFileSync(__dirname  + '/config.json'), 'utf8');\n    return{\n        server:{\n            id:config.server.id,\n            port:config.server.port,\n            isCluster:config.server.isCluster,\n            https:config.server.https,\n            headers:config.server.headers,\n            httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname  + \"/\" + config.server.https.key) :null,\n            httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname  + \"/\" + config.server.https.ca) :null,\n        },\n        api:{\n            route:config.api.route,\n            modules:config.api.modules\n        },\n        serviceRegistry:config.serviceRegistry\n        \n    };\n\n}\nmodule.exports=Config;\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/config.json",
    "content": "{\n  \"server\":{\n    \"id\":\"ServiceOrders\",\n    \"port\":8083,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"orders\", \"route\":\"orders\"}\n    ]\n  },\n  \"serviceRegistry\":{\n      \"watchDog\":{\n        \"isEnabled\":false,\n        \"timer\":30000\n      },\n    \"database\":{\n      \"name\":\"my_mongo_db\",\n      \"user\":\"my_mongo_db_user\",\n      \"password\":\"my_mongo_db_password\",\n      \"host\":\"my_mongo_db_host\",\n      \"port\":27017\n    }\n  }\n}\n\n\n\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/orders.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    debug = require('debug')('http'),\n    config= require ('./config')()\n\nrouter.post('/', function (req, res,next) {\n    return res.status(200).send(\"## Orders -> This is just a test response ;-)\");\n});\n\nmodule.exports = router;"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/package.json",
    "content": "{\n  \"name\": \"MicroNodeService\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Micro Node Tutorial\",\n  \"author\": {\n    \"name\": \"Domenico Vacchiano\",\n    \"email\": \"info@domenicovacchiano.com\",\n    \"url\": \"http://www.domenicovacchiano.com\"\n  },\n  \"homepage\": \"http://www.domenicovacchiano.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"\"\n  },\n  \"engines\": {\n    \"node\": \">= 0.6.0\",\n    \"npm\": \">= 1.0.0\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.13.4\",\n    \"body-parser\": \"^1.15.1\",\n    \"request\": \"^2.72.0\",\n    \"morgan\": \"^1.7.0\",\n    \"network-address\": \"^1.1.0\",\n    \"micro-node-net-lib\": \"git@github.com:alchimya/micro-node-net-lib.git\",\n    \"micro-node-service-registry-lib\": \"git@github.com:alchimya/micro-node-service-registry-lib.git\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node server.js\"\n  },\n  \"main\": \"server.js\"\n}\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-orders/server.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar config= require ('./config')(),\n    address = require('network-address'),\n    express=require('express'),\n    debug = require('debug')('http'),\n    bodyParser = require('body-parser'),\n    morgan= require('morgan'),\n    cluster = require('cluster'),\n    numCPUs = require('os').cpus().length,\n    netLib = require ('micro-node-net-lib'),\n    configServer= {\n        server:{\n            port:config.server.port\n        },\n        https:{\n            isEnabled:config.server.https.isEnabled,\n            key:config.server.httpsKeyContent,\n            ca:config.server.httpsCaContent\n        },\n        express:{\n            app:null\n        },\n        exitHandlers:[\"exit\",\"SIGINT\",\"SIGTERM\"]\n    }\n    server = netLib.server(configServer),\n    serviceRegistry = require ('micro-node-service-registry-lib')({\n        name:config.serviceRegistry.database.name,\n        user:config.serviceRegistry.database.user,\n        password:config.serviceRegistry.database.password,\n        host:config.serviceRegistry.database.host,\n        port:config.serviceRegistry.database.port,\n        connectionPool:config.serviceRegistry.database.connectionPool\n    });\n\n    if (cluster.isMaster && config.server.isCluster) {\n\n        debug(\"cpus:\" + numCPUs);\n        for (var i = 0; i < numCPUs; i++) {\n            cluster.fork();\n        }\n        cluster.on('exit', function(worker, code, signal) {\n            console.log(\"cluster exit\");\n            debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);\n            cluster.fork();\n        });\n\n    } else {\n        \n        var app=express();\n        app.use(bodyParser.urlencoded({ extended: true }));\n        app.use(bodyParser.json());\n        app.use(morgan('dev'));\n        configServer.express.app = app;\n        \n        //header(s) setting\n        app.all('/*', function(req, res, next) {\n            config.server.headers.forEach(function(item) {\n                //console.log(item);\n                res.header(item.name, item.value);\n            });\n            next();\n        });\n\n        //load API route(s)\n        config.api.modules.forEach(function(item) {\n            //console.log(item);\n            app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n        });\n        \n        server.create(function (err,server) {\n            if (!err){\n                //load API route(s) and register services\n                registerServer();\n                if (config.serviceRegistry.watchDog.isEnabled){\n                    setInterval(function(){\n                        registerServer();\n                    }, config.serviceRegistry.watchDog.timer);\n                }\n                console.log(\"### \" + config.server.id + \" -> \" + (config.server.https ? \"HTTPS\" : \"HTTP\") + \" Server started on port \" +\n                    config.server.port + (config.server.isCluster ? \" cluster worker \" + cluster.worker.id : \"\"));\n            } else {\n                debug(err);\n            }\n        });\n\n        server.registerExitHandler(function () {\n            unregisterServer();\n            debug(\"Server Exit Handled\");\n        });\n\n        var registerServer=function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"registerServer\");\n                config.api.modules.forEach(function(item) {\n                    //console.log(item);\n                    app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n                    serviceRegistry.register({\n                        serviceId:config.server.id,\n                        serviceHost:address(),\n                        servicePort:config.server.port,\n                        serviceProtocol:config.server.https.isEnabled ? \"https\" : \"http\",\n                        endpointId:item.name,\n                        endpointPath:config.api.route + \"/\" + item.route\n                    }, function (err,item) {\n                        if (err){\n                            console.log(app.next())\n                            debug(err);\n                        }\n                    });\n                });\n            }\n        };\n        var unregisterServer = function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"unregisterServer\");\n                config.api.modules.forEach(function(item) {\n                    serviceRegistry.unregister(config.server.id,item.name,function (err,item) {\n                        if (err){\n                            //TODO update flag inactive?\n                            console.log(err);\n                        }\n                        if (!config.server.isCluster){\n                            process.exit();\n                        }\n                    });\n                });\n            }\n        };\n  \n\n    }\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/Dockerbuild.sh",
    "content": "docker build -t micro-node-service-signup:latest .\nwinpty docker run -it --rm -p 8082:8082 --name micro-node-service-signup micro-node-service-signup:latest"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/Dockerfile",
    "content": "FROM node:6.2.0-onbuild\nEXPOSE 8082"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/config.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar fs = require('fs');\n\nfunction Config() {\n    var config = JSON.parse(fs.readFileSync(__dirname  + '/config.json'), 'utf8');\n    return{\n        server:{\n            id:config.server.id,\n            port:config.server.port,\n            isCluster:config.server.isCluster,\n            https:config.server.https,\n            headers:config.server.headers,\n            httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname  + \"/\" + config.server.https.key) :null,\n            httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname  + \"/\" + config.server.https.ca) :null,\n        },\n        api:{\n            route:config.api.route,\n            modules:config.api.modules\n        },\n        serviceRegistry:config.serviceRegistry\n        \n    };\n\n}\nmodule.exports=Config;\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/config.json",
    "content": "{\n  \"server\":{\n    \"id\":\"ServiceSignup\",\n    \"port\":8082,\n    \"isCluster\":true,\n    \"https\":{\n      \"isEnabled\":false,\n      \"key\":\"\",\n      \"ca\":\"\"\n    },\n    \"headers\":[\n      {\"name\":\"Access-Control-Allow-Origin\",\"value\":\"*\"},\n      {\"name\":\"Access-Control-Allow-Headers\",\"value\":\"Origin, X-Requested-With, Content-Type, Accept\"},\n      {\"name\":\"Access-Control-Allow-Methods\",\"value\":\"GET,PUT,POST,DELETE,OPTIONS\"}\n    ]\n  },\n  \"api\":{\n    \"route\":\"api\",\n    \"modules\":[\n      {\"name\":\"signup\", \"route\":\"signup\"}\n    ]\n  },\n  \"serviceRegistry\":{\n      \"watchDog\":{\n        \"isEnabled\":false,\n        \"timer\":30000\n      },\n    \"database\":{\n      \"name\":\"my_mongo_db\",\n      \"user\":\"my_mongo_db_user\",\n      \"password\":\"my_mongo_db_password\",\n      \"host\":\"my_mongo_db_host\",\n      \"port\":27017\n    }\n  }\n}\n\n\n\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/package.json",
    "content": "{\n  \"name\": \"MicroNodeService\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Micro Node Tutorial\",\n  \"author\": {\n    \"name\": \"Domenico Vacchiano\",\n    \"email\": \"info@domenicovacchiano.com\",\n    \"url\": \"http://www.domenicovacchiano.com\"\n  },\n  \"homepage\": \"http://www.domenicovacchiano.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"\"\n  },\n  \"engines\": {\n    \"node\": \">= 0.6.0\",\n    \"npm\": \">= 1.0.0\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.13.4\",\n    \"body-parser\": \"^1.15.1\",\n    \"request\": \"^2.72.0\",\n    \"morgan\": \"^1.7.0\",\n    \"network-address\": \"^1.1.0\",\n    \"micro-node-net-lib\": \"git@github.com:alchimya/micro-node-net-lib.git\",\n    \"micro-node-service-registry-lib\": \"git@github.com:alchimya/micro-node-service-registry-lib.git\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node server.js\"\n  },\n  \"main\": \"server.js\"\n}\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/server.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar config= require ('./config')(),\n    address = require('network-address'),\n    express=require('express'),\n    debug = require('debug')('http'),\n    bodyParser = require('body-parser'),\n    morgan= require('morgan'),\n    cluster = require('cluster'),\n    numCPUs = require('os').cpus().length,\n    netLib = require ('micro-node-net-lib'),\n    configServer= {\n        server:{\n            port:config.server.port\n        },\n        https:{\n            isEnabled:config.server.https.isEnabled,\n            key:config.server.httpsKeyContent,\n            ca:config.server.httpsCaContent\n        },\n        express:{\n            app:null\n        },\n        exitHandlers:[\"exit\",\"SIGINT\",\"SIGTERM\"]\n    }\n    server = netLib.server(configServer),\n    serviceRegistry = require ('micro-node-service-registry-lib')({\n        name:config.serviceRegistry.database.name,\n        user:config.serviceRegistry.database.user,\n        password:config.serviceRegistry.database.password,\n        host:config.serviceRegistry.database.host,\n        port:config.serviceRegistry.database.port,\n        connectionPool:config.serviceRegistry.database.connectionPool\n    });\n\n    if (cluster.isMaster && config.server.isCluster) {\n\n        debug(\"cpus:\" + numCPUs);\n        for (var i = 0; i < numCPUs; i++) {\n            cluster.fork();\n        }\n        cluster.on('exit', function(worker, code, signal) {\n            console.log(\"cluster exit\");\n            debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);\n            cluster.fork();\n        });\n\n    } else {\n        \n        var app=express();\n        app.use(bodyParser.urlencoded({ extended: true }));\n        app.use(bodyParser.json());\n        app.use(morgan('dev'));\n        configServer.express.app = app;\n        \n        //header(s) setting\n        app.all('/*', function(req, res, next) {\n            config.server.headers.forEach(function(item) {\n                //console.log(item);\n                res.header(item.name, item.value);\n            });\n            next();\n        });\n\n        //load API route(s)\n        config.api.modules.forEach(function(item) {\n            //console.log(item);\n            app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n        });\n\n        server.create(function (err,server) {\n            if (!err){\n                //load API route(s) and register services\n                registerServer();\n                if (config.serviceRegistry.watchDog.isEnabled){\n                    setInterval(function(){\n                        registerServer();\n                    }, config.serviceRegistry.watchDog.timer);\n                }\n                console.log(\"### \" + config.server.id + \" -> \" + (config.server.https ? \"HTTPS\" : \"HTTP\") + \" Server started on port \" +\n                    config.server.port + (config.server.isCluster ? \" cluster worker \" + cluster.worker.id : \"\"));\n            } else {\n                debug(err);\n            }\n        });\n\n        server.registerExitHandler(function () {\n            unregisterServer();\n            debug(\"Server Exit Handled\");\n        });\n\n        var registerServer=function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"registerServer\");\n                config.api.modules.forEach(function(item) {\n                    //console.log(item);\n                    app.use('/' + config.api.route + \"/\" + item.route, require('./' + item.name));\n                    serviceRegistry.register({\n                        serviceId:config.server.id,\n                        serviceHost:address(),\n                        servicePort:config.server.port,\n                        serviceProtocol:config.server.https.isEnabled ? \"https\" : \"http\",\n                        endpointId:item.name,\n                        endpointPath:config.api.route + \"/\" + item.route\n                    }, function (err,item) {\n                        if (err){\n                            console.log(app.next())\n                            debug(err);\n                        }\n                    });\n                });\n            }\n        };\n        var unregisterServer = function () {\n            if (!config.server.isCluster || cluster.worker.id===1){\n                debug(\"unregisterServer\");\n                config.api.modules.forEach(function(item) {\n                    serviceRegistry.unregister(config.server.id,item.name,function (err,item) {\n                        if (err){\n                            //TODO update flag inactive?\n                            console.log(err);\n                        }\n                        if (!config.server.isCluster){\n                            process.exit();\n                        }\n                    });\n                });\n            }\n        };\n        \n        \n    }\n"
  },
  {
    "path": "api-gateway-and-service-doscovery/service-signup/signup.js",
    "content": "/**\n * Created by domenicovacchiano on 07/07/16.\n */\n\nvar express = require('express'),\n    router = express.Router(),\n    debug = require('debug')('http'),\n    config= require ('./config')()\n\nrouter.post('/', function (req, res,next) {\n    return res.status(200).send(\"## Signup -> This is just a test response ;-)\");\n});\n\nmodule.exports = router;"
  },
  {
    "path": "dockerized-containers/.eslintrc.js",
    "content": "module.exports = {\n  \"extends\": \"airbnb-base\",\n  \"rules\": {\n      \"comma-dangle\": 0,\n      \"no-console\": 0,\n      \"no-unused-vars\" :0\n    }\n};"
  },
  {
    "path": "dockerized-containers/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Node template\n# Logs\nlogs\n*.log\nnpm-debug.log*\n/dist\n.vscode\n/test\n/*/dist\n# Runtime data\npids\n*.pid\n/node_modules\n*.seed\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules\njspm_packages\npackage-lock.json\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n# Jetbrains dir\n.idea/\n.DS_Store\n\n# github dir\n.github/\n\n# .env files\nbin/dev.env\nbin/test.env\n"
  },
  {
    "path": "dockerized-containers/.travis.yml",
    "content": "language: node_js\nsudo: false\nnode_js:\n  - 10\ninstall:\n  - npm install\nscript:\n  - npm test"
  },
  {
    "path": "dockerized-containers/README.md",
    "content": "# Application for e-commerce Hub\n\n\nREST API to support application features\n  - Express as web framework with Typescript\n  - Passport js for social authentication \n  - Express CORS enabled\n  - boom for error codes & Joi for Validation\n  - Winston for logging and express minitor for monitoring\n  - Mongoose as ODM driver\n  - eslint validation extending airbnb styleguide \n  - git hooks & CI/CD in place\n  - Typescript based compilation tsc compiler\n  - TDD in progress with Mocha\n  - JWT based authentication\n  - multiple Mongoose collection with referencing\n  - payment gateway Integration\n  - Heroku deployment\n  - Mini e-commerce platform \n\n# Cart Application #\n\n\"It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills\n - microservices architecture\n - Client application in React\n - User Auth microservices\n - Cart services\n - Admin Microservices  \n\n![deividing services](/screens/02.png \"title\")\n![Micro services with Node JS](/screens/03.png \"title\")\n\n\n\n```\n# Application Execution\n```javascript\ngit clone  repo\nnpm install\nnpm run startdev\ntsc -- watch\n```\n# Application configuration\n```javascript\nenv.sh need to be added locally \nexport NODE_ENV=\"dev\"\nexport PORT=\"3005\"\nexport MONGOURL=\"mongodb://mongo/hello\"\nexport EXPRESS_SESSION_SECRET=\"************************\"\nexport F_CLIENTID=\"**************\"\nexport F_CLIENTSECRET=\"**********************\"\n```\n# update etc/hosts file\n```\n##\n# Host Database\n#\n# localhost is used to configure the loopback interface\n# when the system is booting.  Do not change this entry.\n##\n127.0.0.1       localhost\n255.255.255.255 broadcasthost\n::1             localhost\n127.0.0.1       mysql redis mongo\n127.0.0.1       ms-commerce.com\n```\n# Sevices end-point\n\n- http://ms-commerce.com/api/v1  Auth services\n- http://ms-commerce.com/admin/v1 Admin APIs\n- http://ms-commerce.com/admin/v1  Cart APIs\n\n# Application NPM Script\n```javascript\n\"start\": \"cd dist &&  nodemon server.js\",\n\"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n\"clean\" : \"rm -rf dist\",\n\"copy\" : \"cp -r uploads dist/ && cp -r app/global dist/app/\"\n```\n"
  },
  {
    "path": "dockerized-containers/docker-compose.yml",
    "content": "version: '3.5'\nservices:\n  gateway:\n    image: nginx:1.11\n    ports:\n      - 80:80\n      - 443:443\n    volumes:\n      - ./proxy/default.conf:/etc/nginx/conf.d/default.conf:ro\n      - ./proxy/ssl:/etc/nginx/ssl:ro\n    depends_on:\n      - ms_commerce_auth\n      - ms_commerce_admin\n      - ms_commerce_client\n    networks:\n      - ms_network\n  ms_mysql:\n    container_name: ms_mysql\n    image: mysql:5.7\n    volumes:\n      - ~/datadir/mysql:/var/lib/mysql\n    ports:\n      - 3306:3306\n      - 33060:33060\n    environment:\n      MYSQL_ROOT_PASSWORD: root\n    networks:\n      - ms_network\n  ms_commerce_mongo:\n    image: mongo\n    container_name: ms_commerce_mongo\n    restart: unless-stopped\n    volumes:\n      - ~/datadir/mongo:/data/db\n    ports:\n      - 27017:27017\n    networks:\n      - ms_network\n  ms_commerce_auth:\n    container_name: ms_commerce_auth\n    build: ./e-Commerce-Auth/\n    image: e-commerce-auth\n    volumes:\n      - ./e-Commerce-Auth/:/usr/src/app\n      - /usr/src/app/node_modules\n    ports:\n      - 3001:3001\n      - 9201:9201\n    depends_on:\n      - ms_mysql\n    networks:\n      - ms_network\n  ms_commerce_cart:\n    container_name: ms_commerce_cart\n    build: ./e-Commerce-Cart/\n    image: e-commerce-cart\n    volumes:\n      - ./e-Commerce-Cart/:/usr/src/app\n      - /usr/src/app/node_modules\n    ports:\n      - 3004:3004\n      - 9204:9204\n    depends_on:\n      - ms_mysql\n    networks:\n      - ms_network      \n  ms_commerce_admin:\n    build: ./e-Commerce-Admin/\n    image: e-commerce-admin\n    container_name: ms_commerce_admin\n    environment:\n      - NODE_ENV=local\n    volumes:\n      - ./e-Commerce-Admin/:/usr/src/app\n      - /usr/src/app/node_modules\n    ports:\n      - 3002:3002\n      - 9202:9202\n    depends_on:\n      - ms_commerce_mongo\n    networks:\n      - ms_network\n  ms_commerce_client:\n    build: ./e-Commerce-Client/\n    image: e-commerce-client\n    container_name: ms_commerce_client\n    environment:\n      - NODE_ENV=local\n    volumes:\n      - ./e-Commerce-Client/:/usr/src/app\n      - /usr/src/app/node_modules\n    ports:\n      - 3003:3003\n    depends_on:\n      - ms_commerce_admin\n      - ms_commerce_auth\n    networks:\n      - ms_network      \nnetworks:\n  ms_network:\n    driver: bridge\n    name: ms_network\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/Dockerfile",
    "content": "FROM node:carbon\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Bundle app source\nCOPY . .\n\n# npm install\nRUN  npm install\n# Run npm install --global grpc --unsafe-perm\n\nEXPOSE 3002 9202\nCMD [ \"npm\", \"run\", \"watchserver\" ]\nCMD [ \"npm\", \"run\", \"startdev\" ]\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/README.md",
    "content": "# Application for e-commerce Hub\n\n\nREST API to support application features\n\n  - Express as web framework with Typescript\n  - Passport js for social authentication \n  - Express CORS enabled\n  - boom for error codes & Joi for Validation\n  - Winston for logging and express minitor for monitoring\n  - Mongoose as ODM driver\n  - eslint validation extending airbnb styleguide \n  - git hooks & CI/CD in place\n  - Typescript based compilation tsc compiler\n  - TDD in progress with Mocha\n  - JWT based authentication\n  - multiple Mongoose collection with referencing\n  - payment gateway Integration\n  - Heroku deployment\n  - Mini e-commerce platform \n\n# Cart Application #\n\n\"It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills\n\n```\n# Application Execution\n```javascript\ngit clone  repo\nnpm install\nnpm run startdev\ntsc -- watch\n```\n# Application configuration\n```javascript\nenv.sh need to be added locally \nexport NODE_ENV=\"dev\"\nexport PORT=\"3005\"\nexport MONGOURL=\"mongodb://mongo/hello\"\nexport EXPRESS_SESSION_SECRET=\"************************\"\nexport F_CLIENTID=\"**************\"\nexport F_CLIENTSECRET=\"**********************\"\n```\n\n# Application NPM Script\n```javascript\n\"start\": \"cd dist &&  nodemon server.js\",\n\"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n\"clean\" : \"rm -rf dist\",\n\"copy\" : \"cp -r uploads dist/ && cp -r app/global dist/app/\"\n```\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/config/email.ts",
    "content": "'use strict';\n\nexport default {\n\n  global: {\n    from: 'info@kpilibrary.com',\n  },\n  welcome: {\n    subject: 'Welcome to KPI Library',\n  },\n  password_reset: {\n    subject: 'KPI Library: Reset your password',\n  },\n  event_booked_guest: {\n    subject: 'KPI Library: Your Booking Has Been Confirmed',\n  },\n  event_booked_host: {\n    subject: 'KPI Library: Your Event Has Been Booked',\n  },\n  event_booked_guests_notification: {\n    subject: 'KPI Library: Your Booking Has Been Confirmed',\n  },\n  message_received: {\n    subject: 'KPI Library: New Message Received',\n  },\n  guest_review_email: {\n    subject: 'KPI Library: Event Completed',\n  },\n  alacarte_booked_guest: {\n    subject: 'KPI Library: Alacarte Booking Details',\n  },\n  alacarte_booked_host: {\n    subject: 'KPI Library: Your Alacarte Has Been Booked',\n  }\n}\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/config/environments/dev.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\n\nmodule.exports = configuration;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/config/environments/qa.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nmodule.exports = configuration;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/config/environments/test.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nmodule.exports = configuration;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/controller/UserController.ts",
    "content": "export { };\nconst uuidv4 = require('uuid/v4');\nimport User from '../models/user';\ndeclare function require(name: string);\nimport Helper from '../helper/bcrypt';\nconst jwt = require('jsonwebtoken');\nimport helper from '../helper/bcrypt';\nimport mailEvents from '../events/notification';\nimport logger from '../helper/logger';\nimport email from '../helper/email';\n\nconst saltRounds = 10;\nclass userController {\n\n  static getUserByEmail(email, cb) {\n    User.findOne({ 'email': email }, (error, user) => {\n      if (user) {\n        cb(null, user);\n      } else {\n        cb('User does not exist in system', null);\n      }\n    });\n  }\n  static validateUser(req, res, cb) {\n    const { body } = req;\n    User.find({ email: body.email })\n      .then((data) => {\n        if (data && data.length) {\n          const flag = helper.comparePassword(body.password, data[0].password)\n          if (flag) {\n            jwt.sign(helper.buildUserToken(data[0]), 'secretkey', (tokError, token) => {\n              cb(null, token);\n            });\n          } else {\n            cb(new Error('username password does not match'), null);\n          }\n        }\n        else {\n          cb(new Error('no user found with this account email'), null);\n        }\n      });\n  }\n  static registerDefault(req, res, cb) {\n    const { body } = req;\n    const { location } = req;\n    const hash = helper.generateSaltValue(body.password);\n    return User.find({ email: body.email }).then((user) => {\n      if (user && user.length > 0) {\n        cb(new Error('user already regitsered with us'), null);\n      } else {\n        return User.create(this.buildUser(body, hash, location)\n          , (error, user) => {\n            if (error) {\n              cb(error, null);\n            } else {\n              logger.info('emitting user create event');\n              mailEvents.emit(\"welcome\", user);\n              cb(null, user);\n            }\n          });\n      }\n    });\n  }\n  static buildUser(body, hash = null, location = null) {\n\n    const build = {\n      username: body.username,\n      phone: body.phone,\n      email: body.email,\n      email_verified: false,\n      phone_verified: false,\n      picture: body.picture ? body.picture : null,\n      status: 1,\n      gender: null,\n      documents: [],\n      type: 1,\n      social: body.meta,\n      uuid: uuidv4()\n    }\n    return hash ? Object.assign({}, build, { password: hash }) : build;\n  }\n  static registerSocial(user, callback) {\n      User.findOne({ email: user.email }, (error, existingUser) => {\n        if (existingUser) {\n          callback(null, (existingUser));\n        } else {\n          User.create(this.buildUser(user, null), (err, user) => {\n            if (err) {\n              callback(err, null);\n            } else {\n              callback(null, user);\n              mailEvents.emit(\"welcome\", user);\n            }\n          });\n        }\n      });\n\n  }\n\n  static activateUserAccount(uuid, cb) {\n    User.findOne({ 'uuid': uuid }, (error, foundUser) => {\n      if (foundUser) {\n        foundUser.email_verified = true;\n        foundUser.save(function (err) {\n          if (err) {\n            cb('error occoured while updating record');\n          } else {\n            cb(null, 'done');\n          }\n        });\n      } else {\n        cb('User does not exist in system');\n      }\n    });\n  }\n  static resetPassword(email, callback) {\n    // just generate password and send new password on mail\n    User.findOne({ 'email': email }, (error, foundUser) => {\n      if (foundUser) {\n        let password = Math.random().toString(36).slice(2);\n        const hash = helper.generateSaltValue(password);\n        foundUser.password = hash;\n        foundUser.save(function (err) {\n          if (err) {\n            callback('error occoured while updating record');\n          } else {\n            mailEvents.emit(\"forgotPassword\", foundUser, password);\n            callback(null, 'done');\n          }\n        });\n      } else {\n        callback('User does not exist in system with this email');\n      }\n    });\n  }\n\n  static changeUserRole(req, callback) {\n    const email = req.params.email\n    const body = req.body\n    User.findOne({ 'email': email }, (error, user) => {\n      if (user) {\n        user.type = 2;\n        user.save(function (err, updated_user) {\n          if (err) {\n            callback('error occoured while chaging role');\n          } else {\n            callback(null, updated_user);\n          }\n        });\n      }\n      else {\n        callback('user not found in system', null);\n      }\n    });\n  }\n\n  static updateUser(email, data, callback) {\n    User.findOne({ 'email': email }, (error, user) => {\n      if (user) {\n        if (data.username) { user.username = data.username; }\n        if (data.gender) { user.gender = data.gender; }\n        if (data.phone) { user.phone = data.phone; }\n        if (data.profile_picture) { user.profile_picture = data.profile_picture; }\n        if (data.password && data.password === data.confirm_password) {\n          const hash = helper.generateSaltValue(data.password);\n          user.password = hash;\n        }\n        if ( data.picture ) { user.picture = Helper.avatarURL(data.picture) }\n\n        if (data.phone_verified) {\n          user.phone_verified = true;\n        }\n        if (data.document) {\n          user.documents.push(data.document);\n        }\n        if (data.meta) {\n          user.meta = {\n            about: data.meta.about || '',\n            fun_fact: data.meta.fun_fact || '',\n            payment: data.meta.payment || '',\n          }\n        }\n        user.save(function (err, updated_user) {\n          if (err) {\n            callback('error occoured while updating record');\n          } else {\n            callback(null, updated_user);\n          }\n        });\n      } else {\n        callback('user not found', null);\n      }\n    });\n  }\n}\n\nexport default userController;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/events/notification.ts",
    "content": "\nimport Email from '../helper/email';\ndeclare function require(name: string);\n\nconst events = require('events');\nconst winston = require('winston');\n// import Twillo from '../helper/twillo';\n\nconst eventEmitter = new events.EventEmitter();\neventEmitter.on('welcome', (user) => {\n  winston.log('info', `sending welcome email to ${user.email}`);\n  // Twillo.default_notification(user.phone, 'welcome')\n  Email.welcome(user);\n});\neventEmitter.on('forgotPassword', (user, password, uuid) => {\n  winston.log('info', `sending forgotPassword email to ${user.email}`);\n  Email.password_reset(user, password);\n  // Twillo.default_notification(user.phone, 'welcome')\n});\n\nexport default eventEmitter;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/global/templates/emails/password-reset-email/html.pug",
    "content": "html(lang='en')\n  head\n    meta(charset='utf-8')\n    meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no')\n    title  password has successfully been reset\n    link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet')\n    link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico')\n    link(rel='stylesheet', href='../assets/styles/style.css', type='text/css')\n  body(data-gr-c-s-loaded='true', style='')\n    .template-wrapper\n    table.body(border='0', cellpadding='0', cellspacing='0')\n      tbody\n        tr\n          td  \n          td.container\n            .content\n              table.main\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              a.template-logo(href='../index.html')\n                                img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='')\n                              p.lead\n                                | Hello #{user.email}, \n                                br\n                                | Your password has successfully been reset\n                              table(border='0', cellpadding='0', cellspacing='0')\n                                tbody\n                                  tr\n                                    td.mt30.mb30(align='center')\n                                      table(border='0', cellpadding='0', cellspacing='0')\n                                        tbody\n                                          tr\n                                            td\n                                              p.user-text\n                                                span  Your new password is #[pre #{password}]\n                                                br\n                                                a.btn-primary(href= login_url) Login \n                              p Thank you\n                              p.mb0\n                                | If you have any problems, please contact me at \n                                a.click-link(href='#') admin@gmail.com\n              table.help-section\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              h2.text-center.mb0 Need more help?\n                              a.support-link(href='#') We're here,ready to here\n              table\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              p\n                                | You received this email beacuse you just signed up for new account. If it look weird\n                                a.default-link(href='#') view it in your browser\n                  .footer\n                    table(border='0', cellpadding='0', cellspacing='0')\n                      tbody\n                        tr\n                          td.content-block\n                            p.text-center\n                              | © 2018 KPI App, Goa India\n                              br\n                              |  If these emails get annoying, please feel to \n                              a(href='#') unsubscribe\n          td  \n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/global/templates/emails/password-reset-email/style.css",
    "content": "@charset \"UTF-8\";\n/* -------------------------------------\n          GLOBAL RESETS\n      ------------------------------------- */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\nimg {\n  border: none;\n  -ms-interpolation-mode: bicubic;\n  max-width: 100%;\n}\n\nbody {\n  background-color: #f6f6f6;\n  font-family: 'Rubik', sans-serif;\n  font-size: 15px;\n  line-height: 28px;\n  -webkit-font-smoothing: antialiased;\n  margin: 0;\n  padding: 0;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n\ntable {\n  border-collapse: separate;\n  mso-table-lspace: 0pt;\n  mso-table-rspace: 0pt;\n  width: 100%;\n}\n\ntable td {\n  font-family: sans-serif;\n  font-size: 14px;\n  vertical-align: top;\n}\n\n/* -------------------------------------\n          BODY & CONTAINER\n      ------------------------------------- */\n\n.body {\n  background-color: #f6f6f6;\n  width: 100%;\n}\n\n.lead {\n  font-size: 18px;\n}\n\n.mt30 {\n  margin-top: 30px;\n  display: block;\n}\n\n.mb30 {\n  margin-bottom: 30px;\n  display: block;\n}\n\n/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  /* makes it centered */\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\n/* This should also be a block element, so that it will fill 100% of the .container */\n\n.content {\n  box-sizing: border-box;\n  display: block;\n  Margin: 0 auto;\n  max-width: 580px;\n  padding: 10px;\n}\n\n/* -------------------------------------\n          HEADER, FOOTER, MAIN\n      ------------------------------------- */\n\n.template-wrapper {\n  background-color: #03A9F4;\n  width: 100%;\n  height: 250px;\n  position: relative;\n}\n\n.click-link {\n  color: #03A9F4;\n  display: inline-block;\n  margin-bottom: 20px;\n}\n\n.help-section {\n  background-color: #ffdcdc;\n  border-radius: 3px;\n  width: 100%;\n  text-align: center;\n}\n\n.mb0 {\n  margin-bottom: 0px;\n}\n\n.support-link {\n  color: #03A9F4;\n  display: inline-block;\n  font-size: 19px;\n  margin-bottom: 0px;\n}\n\n.template-logo {\n  display: block;\n  margin-bottom: 40px;\n  margin: auto;\n}\n\n.user-text {\n  font-size: 18px;\n  font-weight: 500;\n}\n\n.user-text span {\n  font-weight: 600;\n}\n\n.text-secondary {\n  color: #218ef4 !important\n}\n\n.main {\n  background: #ffffff;\n  border-radius: 3px;\n  width: 100%;\n  margin-bottom: 20px;\n}\n\n.wrapper {\n  box-sizing: border-box;\n  padding: 40px 25px;\n}\n\n.content-block {\n  padding-bottom: 10px;\n  padding-top: 10px;\n  line-height: 2;\n}\n\n.footer {\n  clear: both;\n  text-align: center;\n  width: 100%;\n}\n\n.footer td, .footer p, .footer span, .footer a {\n  color: #999999;\n  font-size: 12px;\n  text-align: center;\n}\n\n/* -------------------------------------\n          TYPOGRAPHY\n      ------------------------------------- */\n\nh1, h2, h3, h4 {\n  color: #000000;\n  font-family: sans-serif;\n  font-weight: 400;\n  line-height: 1.4;\n  margin: 0;\n  Margin-bottom: 30px;\n}\n\nh1 {\n  font-size: 35px;\n  font-weight: 300;\n  text-align: center;\n  text-transform: capitalize;\n}\n\np, ul, ol {\n  font-family: sans-serif;\n  font-size: 15px;\n  font-weight: normal;\n  margin: 0;\n  margin-bottom: 15px;\n}\n\np li, ul li, ol li {\n  list-style-position: inside;\n  margin-left: 5px;\n}\n\na {\n  color: #3498db;\n  text-decoration: underline;\n}\n\n/* -------------------------------------\n          BUTTONS\n      ------------------------------------- */\n\n.btn {\n  box-sizing: border-box;\n  width: 100%;\n}\n\n.btn>tbody>tr>td {\n  padding-bottom: 15px;\n}\n\n.btn table {\n  width: auto;\n}\n\n.btn table td {\n  background-color: #ffffff;\n  border-radius: 5px;\n  text-align: center;\n}\n\n.btn a {\n  background-color: #ffffff;\n  border: solid 1px #3498db;\n  border-radius: 5px;\n  box-sizing: border-box;\n  color: #3498db;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 14px;\n  font-weight: bold;\n  margin: 0;\n  padding: 12px 25px;\n  text-decoration: none;\n  text-transform: capitalize;\n}\n\n.btn-primary table td {\n  background-color: #3498db;\n}\n\n.btn-primary a {\n  background-color: #03A9F4;\n  border-color: #03A9F4;\n  color: #ffffff;\n}\n\n.default-link {\n  color: #03A9F4;\n}\n\n.default-link:hover {\n  color: #03A9F4;\n}\n\n/* -------------------------------------\n          OTHER STYLES THAT MIGHT BE USEFUL\n      ------------------------------------- */\n\n.last {\n  margin-bottom: 0;\n}\n\n.first {\n  margin-top: 0;\n}\n\n.align-center {\n  text-align: center;\n}\n\n.align-right {\n  text-align: right;\n}\n\n.align-left {\n  text-align: left;\n}\n\n.clear {\n  clear: both;\n}\n\n.mt0 {\n  margin-top: 0;\n}\n\n.mb0 {\n  margin-bottom: 0;\n}\n\n.preheader {\n  color: transparent;\n  display: none;\n  height: 0;\n  max-height: 0;\n  max-width: 0;\n  opacity: 0;\n  overflow: hidden;\n  visibility: hidden;\n  width: 0;\n}\n\n.powered-by a {\n  text-decoration: none;\n}\n\nhr {\n  border: 0;\n  border-bottom: 1px solid #f6f6f6;\n  Margin: 20px 0;\n}\n\n/* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n\n@media only screen and (max-width: 620px) {\n  table[class=body] h1 {\n    font-size: 28px !important;\n    margin-bottom: 10px !important;\n  }\n  table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a {\n    font-size: 16px !important;\n  }\n  table[class=body] .wrapper, table[class=body] .article {\n    padding: 10px !important;\n  }\n  table[class=body] .content {\n    padding: 0 !important;\n  }\n  table[class=body] .container {\n    padding: 0 !important;\n    width: 100% !important;\n  }\n  table[class=body] .main {\n    border-left-width: 0 !important;\n    border-radius: 0 !important;\n    border-right-width: 0 !important;\n  }\n  table[class=body] .btn table {\n    width: 100% !important;\n  }\n  table[class=body] .btn a {\n    width: 100% !important;\n  }\n  table[class=body] .img-responsive {\n    height: auto !important;\n    max-width: 100% !important;\n    width: auto !important;\n  }\n}\n\n/* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n\n@media all {\n  .ExternalClass {\n    width: 100%;\n  }\n  .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {\n    line-height: 100%;\n  }\n  .apple-link a {\n    color: inherit !important;\n    font-family: inherit !important;\n    font-size: inherit !important;\n    font-weight: inherit !important;\n    line-height: inherit !important;\n    text-decoration: none !important;\n  }\n  .btn-primary table td:hover {\n    background-color: #34495e !important;\n  }\n  .btn-primary a:hover {\n    background-color: #03A9F4 !important;\n    border-color: #03A9F4 !important;\n  }\n}\n.btn-primary {\n  text-decoration: none;\n  color: #FFF;\n  background-color: #03A9F4;\n  border: solid #03A9F4;\n  border-width: 6px 18px;\n  line-height: 2em;\n  /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */\n  /*line-height: 28px;*/\n  font-weight: bold;\n  text-align: center;\n  cursor: pointer;\n  display: inline-block;\n  border-radius: 4px;\n  text-transform: capitalize;\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/global/templates/emails/welcome-email/html.pug",
    "content": "html(lang='en')\n  head\n    meta(charset='utf-8')\n    meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no')\n    title Account Activation email || KPI Library\n    link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet')\n    link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico')\n    link(rel='stylesheet', href='../assets/styles/style.css', type='text/css')\n  body(data-gr-c-s-loaded='true', style='')\n    .template-wrapper\n    table.body(border='0', cellpadding='0', cellspacing='0')\n      tbody\n        tr\n          td  \n          td.container\n            .content\n              table.main\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              a.template-logo(href='../index.html')\n                                img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='')\n                              p.lead\n                                | Hello KPI Library, \n                                br\n                                | Thanks for Signup on KPI App\n                                br\n                                | We have sent User Account Activation Link below\n                              table(border='0', cellpadding='0', cellspacing='0')\n                                tbody\n                                  tr\n                                    td.mt30.mb30(align='center')\n                                      table(border='0', cellpadding='0', cellspacing='0')\n                                        tbody\n                                          tr\n                                            td\n                                              p.user-text\n                                                | Hi,\n                                                span #{user.email},\n                                                br\n                                                br\n                                                a.btn-primary(href= activate_url) Activate  your Account\n                              p Thank you\n                              p.mb0\n                                | If you have any problems, please contact me at \n                                a.click-link(href='#') admin@gmail.com\n              table.help-section\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              h2.text-center.mb0 Need more help?\n                              a.support-link(href='#') We're here,ready to here\n              table\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              p\n                                | You received this email beacuse you just signed up for new account. If it look weird\n                                a.default-link(href='#') view it in your browser\n                  .footer\n                    table(border='0', cellpadding='0', cellspacing='0')\n                      tbody\n                        tr\n                          td.content-block\n                            p.text-center\n                              | © 2018 KPI App, Goa India\n                              br\n                              |  If these emails get annoying, please feel to \n                              a(href='#') unsubscribe\n          td  \n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/global/templates/emails/welcome-email/style.css",
    "content": "@charset \"UTF-8\";\n/* -------------------------------------\n          GLOBAL RESETS\n      ------------------------------------- */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\nimg {\n  border: none;\n  -ms-interpolation-mode: bicubic;\n  max-width: 100%;\n}\n\nbody {\n  background-color: #f6f6f6;\n  font-family: 'Rubik', sans-serif;\n  font-size: 15px;\n  line-height: 28px;\n  -webkit-font-smoothing: antialiased;\n  margin: 0;\n  padding: 0;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n\ntable {\n  border-collapse: separate;\n  mso-table-lspace: 0pt;\n  mso-table-rspace: 0pt;\n  width: 100%;\n}\n\ntable td {\n  font-family: sans-serif;\n  font-size: 14px;\n  vertical-align: top;\n}\n\n/* -------------------------------------\n          BODY & CONTAINER\n      ------------------------------------- */\n\n.body {\n  background-color: #f6f6f6;\n  width: 100%;\n}\n\n.lead {\n  font-size: 18px;\n}\n\n.mt30 {\n  margin-top: 30px;\n  display: block;\n}\n\n.mb30 {\n  margin-bottom: 30px;\n  display: block;\n}\n\n/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  /* makes it centered */\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\n/* This should also be a block element, so that it will fill 100% of the .container */\n\n.content {\n  box-sizing: border-box;\n  display: block;\n  Margin: 0 auto;\n  max-width: 580px;\n  padding: 10px;\n}\n\n/* -------------------------------------\n          HEADER, FOOTER, MAIN\n      ------------------------------------- */\n\n.template-wrapper {\n  background-color: #03A9F4;\n  width: 100%;\n  height: 250px;\n  position: relative;\n}\n\n.click-link {\n  color: #03A9F4;\n  display: inline-block;\n  margin-bottom: 20px;\n}\n\n.help-section {\n  background-color: #ffdcdc;\n  border-radius: 3px;\n  width: 100%;\n  text-align: center;\n}\n\n.mb0 {\n  margin-bottom: 0px;\n}\n\n.support-link {\n  color: #03A9F4;\n  display: inline-block;\n  font-size: 19px;\n  margin-bottom: 0px;\n}\n\n.template-logo {\n  display: block;\n  margin-bottom: 40px;\n  margin: auto;\n}\n\n.user-text {\n  font-size: 18px;\n  font-weight: 500;\n}\n\n.user-text span {\n  font-weight: 600;\n}\n\n.text-secondary {\n  color: #218ef4 !important\n}\n\n.main {\n  background: #ffffff;\n  border-radius: 3px;\n  width: 100%;\n  margin-bottom: 20px;\n}\n\n.wrapper {\n  box-sizing: border-box;\n  padding: 40px 25px;\n}\n\n.content-block {\n  padding-bottom: 10px;\n  padding-top: 10px;\n  line-height: 2;\n}\n\n.footer {\n  clear: both;\n  text-align: center;\n  width: 100%;\n}\n\n.footer td, .footer p, .footer span, .footer a {\n  color: #999999;\n  font-size: 12px;\n  text-align: center;\n}\n\n/* -------------------------------------\n          TYPOGRAPHY\n      ------------------------------------- */\n\nh1, h2, h3, h4 {\n  color: #000000;\n  font-family: sans-serif;\n  font-weight: 400;\n  line-height: 1.4;\n  margin: 0;\n  Margin-bottom: 30px;\n}\n\nh1 {\n  font-size: 35px;\n  font-weight: 300;\n  text-align: center;\n  text-transform: capitalize;\n}\n\np, ul, ol {\n  font-family: sans-serif;\n  font-size: 15px;\n  font-weight: normal;\n  margin: 0;\n  margin-bottom: 15px;\n}\n\np li, ul li, ol li {\n  list-style-position: inside;\n  margin-left: 5px;\n}\n\na {\n  color: #3498db;\n  text-decoration: underline;\n}\n\n/* -------------------------------------\n          BUTTONS\n      ------------------------------------- */\n\n.btn {\n  box-sizing: border-box;\n  width: 100%;\n}\n\n.btn>tbody>tr>td {\n  padding-bottom: 15px;\n}\n\n.btn table {\n  width: auto;\n}\n\n.btn table td {\n  background-color: #ffffff;\n  border-radius: 5px;\n  text-align: center;\n}\n\n.btn a {\n  background-color: #ffffff;\n  border: solid 1px #3498db;\n  border-radius: 5px;\n  box-sizing: border-box;\n  color: #3498db;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 14px;\n  font-weight: bold;\n  margin: 0;\n  padding: 12px 25px;\n  text-decoration: none;\n  text-transform: capitalize;\n}\n\n.btn-primary table td {\n  background-color: #3498db;\n}\n\n.btn-primary a {\n  background-color: #3498db;\n  border-color: #3498db;\n  color: #ffffff;\n}\n\n.default-link {\n  color: #3498db;\n}\n\n.default-link:hover {\n  color: #3498db;\n}\n\n/* -------------------------------------\n          OTHER STYLES THAT MIGHT BE USEFUL\n      ------------------------------------- */\n\n.last {\n  margin-bottom: 0;\n}\n\n.first {\n  margin-top: 0;\n}\n\n.align-center {\n  text-align: center;\n}\n\n.align-right {\n  text-align: right;\n}\n\n.align-left {\n  text-align: left;\n}\n\n.clear {\n  clear: both;\n}\n\n.mt0 {\n  margin-top: 0;\n}\n\n.mb0 {\n  margin-bottom: 0;\n}\n\n.preheader {\n  color: transparent;\n  display: none;\n  height: 0;\n  max-height: 0;\n  max-width: 0;\n  opacity: 0;\n  overflow: hidden;\n  visibility: hidden;\n  width: 0;\n}\n\n.powered-by a {\n  text-decoration: none;\n}\n\nhr {\n  border: 0;\n  border-bottom: 1px solid #f6f6f6;\n  Margin: 20px 0;\n}\n\n/* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n\n@media only screen and (max-width: 620px) {\n  table[class=body] h1 {\n    font-size: 28px !important;\n    margin-bottom: 10px !important;\n  }\n  table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a {\n    font-size: 16px !important;\n  }\n  table[class=body] .wrapper, table[class=body] .article {\n    padding: 10px !important;\n  }\n  table[class=body] .content {\n    padding: 0 !important;\n  }\n  table[class=body] .container {\n    padding: 0 !important;\n    width: 100% !important;\n  }\n  table[class=body] .main {\n    border-left-width: 0 !important;\n    border-radius: 0 !important;\n    border-right-width: 0 !important;\n  }\n  table[class=body] .btn table {\n    width: 100% !important;\n  }\n  table[class=body] .btn a {\n    width: 100% !important;\n  }\n  table[class=body] .img-responsive {\n    height: auto !important;\n    max-width: 100% !important;\n    width: auto !important;\n  }\n}\n\n/* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n\n@media all {\n  .ExternalClass {\n    width: 100%;\n  }\n  .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {\n    line-height: 100%;\n  }\n  .apple-link a {\n    color: inherit !important;\n    font-family: inherit !important;\n    font-size: inherit !important;\n    font-weight: inherit !important;\n    line-height: inherit !important;\n    text-decoration: none !important;\n  }\n  .btn-primary table td:hover {\n    background-color: #34495e !important;\n  }\n  .btn-primary a:hover {\n    background-color: #03A9F4 !important;\n    border-color: #03A9F4 !important;\n  }\n}\n.btn-primary {\n  text-decoration: none;\n  color: #FFF;\n  background-color: #03A9F4;\n  border: solid #03A9F4;\n  border-width: 6px 18px;\n  line-height: 2em;\n  /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */\n  /*line-height: 28px;*/\n  font-weight: bold;\n  text-align: center;\n  cursor: pointer;\n  display: inline-block;\n  border-radius: 4px;\n  text-transform: capitalize;\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/global/templates/response/index.ts",
    "content": "class ResponseTemplate {\n  static general(data) {\n    return data;\n  }\n  static error(code, message, description) {\n    return {\n      statusCode: code || 400,\n      message: message || 'some error occoured',\n      description: description || 'error occoured on server, please try again after some time.'\n    };\n  }\n  static authError() {\n    return this.error(\n      403,\n      'authentication error',\n      'no authentication token provided, please login first and provide the authentication token.'\n    );\n  }\n  static invalidAuthError() {\n    return this.error(\n      403,\n      'authentication error',\n      'invalid Token provided, please login first and provide the authentication token.'\n    );\n  }\n  static emptyContent() {\n    return this.general({\n      statusCode: 402,\n      message: 'empty content found',\n      description: 'you must provide valid data and it must not be empty.',\n      helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json']\n    });\n  }\n  static invalidContentType() {\n    return this.general({\n      statusCode: 400,\n      message: 'invalid content type',\n      description: 'you must specify content type and it must be application/json',\n      helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type']\n    });\n  }\n  static routeNotFound() {\n    return this.error(\n      405,\n      'resource not found',\n      'the resource your tried to access doesn\\'t exist or you dont have permissions to access it.'\n    );\n  }\n  static userNotFound() {\n    return this.error(\n      400,\n      'user not found',\n      \"the user you're looking for doesn't exist or you dont have permissions to access it.\"\n    );\n  }\n  static updateErrorOccoured(error) {\n    return this.error(\n      301,\n      'error occoured',\n      error || 'error occoured while updating your data.'\n    );\n  }\n  static success(description, data=null) {\n\t\treturn {\n\t\t\tstatusCode: 200,\n\t\t\tmessage: 'success',\n\t\t\tdescription: description || 'data successfully saved.',\n\t\t\t...data\n\t\t}\n\t}\n}\n\nexport default ResponseTemplate;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/helper/bcrypt.ts",
    "content": "\nconst bcrypt = require('bcrypt-nodejs');\nconst jwt = require('jsonwebtoken');\nconst {url} = global['configuration']\nconst {uploadpath} = global['configuration']\nconst path = require('path');\nconst fs = require('fs');\nconst helper = {\n  generateSaltValue(password) {\n    const salt = bcrypt.genSaltSync(); // enter number of rounds, default: 10\n    const hash = bcrypt.hashSync(password, salt);\n    return hash;\n  },\n  comparePassword(userPassword, password ) {\n    if (!userPassword.length ||  !( password && password.length > 0) ) {\n      return false;\n    }\n    return bcrypt.compareSync(userPassword, password);\n  },\n  authRedirectUrl( path ) {\n\t\treturn `${url.FE}/#/auth/validate-token/${path}`;\n\t},\n\t\n  buildUserToken(data) {\n    return {\n        email: data.email,\n        id:data._id,\n        username: data.username ? data.username : data.email,\n        hasPassword: data.password ? true : false,\n        type : data.type || 1,\n        picture : data.picture\n    }\n  },\n  resource( path ) {\n\t\treturn `${url.API}${path}`;\n\t},\n  getFileExtension( file ) {\n\t\tlet extensions = file.split('.');\n\t\tif ( extensions.length === 1 ) {\n\t\t\treturn 'jpg';\n\t\t} else {\n\t\t\treturn extensions.pop();\n\t\t}\n\t},\n\tavatarURL( filename ) {\n\t\tif ( filename.includes('://') ) {\n\t\t\treturn filename;\n\t\t}\n\t\treturn this.resource(`/${uploadpath.uploaddir}/${uploadpath.profiledir}/${filename}`);\n\t},\n\tuserDocumentURL( filename ) {\n\t\tif ( filename.includes('://') ) {\n\t\t\treturn filename;\n\t\t}\n\t\treturn this.resource(`/${uploadpath.uploaddir}/${uploadpath.documentdir}/${filename}`);\n\t},\n\trandomString() {\n\t\treturn Math.random().toString(36).substring(2, 7);\n  },\n  deleteFile( type, filename ) {\n\t\tlet location;\n    if ( type === 'profile' ) { location = path.join( uploadpath.uploaddir, uploadpath.profiledir ) }\n\t\telse { location = uploadpath.uploaddir; }\n\t\tif (filename) {\n\t\t\tfs.unlink( path.join( location, filename ), () => {\n\t\t\t\t// in case we need to perform additional operations.\n\t\t\t});\n\t\t}\n\t},\n\tgetPaymentMethodName( method ) {\n\t\tif ( method == 1 ) { return 'PayPal'; }\n\t\telse if ( method == 2 ) { return 'PayPal'; }\n\t\telse if ( method == 3 ) { return 'Instamojo'; }\n\t\telse { return 'Not Specified'; }\n\t},\n\tgetCurrency(currency) {\n\t\tlet allCurrency = {\n\t\t\t1: 'USD',\n\t\t\t2: 'INR',\n\t\t};\n\n\t\tif( allCurrency[currency] ) {\n\t\t\treturn allCurrency[currency];\n\t\t} else {\n\t\t\treturn allCurrency[1];\n\t\t}\n\n\t},\n\tverificationCode() {\n\t\tlet code = Math.floor((Math.random()*999999)+111111);\n\t\treturn code;\n\t}\n};\n\nexport default helper;\n\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/helper/email.ts",
    "content": "const path = require('path');\ndeclare function require(name:string);\n\nconst nodemailer = require('nodemailer');\nconst url = global['configuration'].url;\nconst mailConfig = global['configuration'].email;\n\nimport emailConfig from '../config/email';\nimport { EmailTemplate } from 'email-templates';\n// const Twillo = require('./twillo');\n\n  const transport = nodemailer.createTransport({\n    host: 'smtp.gmail.com',\n    port: 465,\n    secure: true,\n    auth: {\n      // type: 'OAuth2',\n      user: mailConfig.auth.user,\n      pass:  mailConfig.auth.pass\n    },\n  });\nconst Email = {\n  welcome(user) {\n    if (user.email) {\n      let templateDir = path.join('app/global/templates', 'emails', 'welcome-email');\n      let welcomeEmail = new EmailTemplate(templateDir);\n      welcomeEmail.render({ user: user, activate_url: `${url.API}/auth/activate/${user.uuid}` }, (err, result) => {\n        transport.sendMail(\n          {\n            from: emailConfig.global.from,\n            to: user.email,\n            subject: emailConfig.welcome.subject,\n            html: result.html,\n          }, (err, info) => {\n            // some error occoured...\n            console.log(err);\n          }\n        );\n      });\n    }\n  },\n  password_reset(user, password) {\n    if (user.email) {\n      let templateDir = path.join('app/global/templates', 'emails', 'password-reset-email');\n      let passwordResetEmail = new EmailTemplate(templateDir);\n      passwordResetEmail.render({ user: user, login_url: `${url.FE}/#/auth/login`, password: password }, (err, result) => {\n        transport.sendMail(\n          {\n            from: emailConfig.global.from,\n            to: user.email,\n            subject: emailConfig.password_reset.subject,\n            html: result.html,\n          }, (err, info) => {\n            // some error occoured...\n          }\n        );\n      });\n    }\n    if (user.phone_verified) {\n      // Twillo.password_reset_notification(user.phone);\n    }\n\n  },\n};\nexport default Email;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/helper/errorHandler.ts",
    "content": "import * as winston from 'winston';\nimport  ResponseTemplate from './responseTemplate';\n/* eslint class-methods-use-this:0 */\nconst env = process.env.NODE_ENV;\nconst onDevEnv = env === 'dev' || env === 'test' || env === 'local';\nclass errorHandler {\n  public internalServerError(err, req, res, next) {\n    winston.log('info',err);\n    if (err.isBoom) {\n      // Error From  joi express validator\n      const error = {\n        message: err.output.payload.error,\n        error: err.output.payload.message\n      };\n      res.status(400).json(ResponseTemplate.BadRequestFromJoi(error));\n    } else { // internalServerError\n      res.status(500).json({\n        success: false,\n        message: err.message,\n        error: (onDevEnv) ? err.stack : {}\n      });\n    }\n  }\n  public PageNotFound(req, res, err) {\n    res.status(404).json({ message: 'api not found' });\n  }\n}\n\nexport default new errorHandler();\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/helper/logger.ts",
    "content": "const winston = require('winston');\n\n// define the custom settings for each transport (file, console)\nconst options = {\n  console: {\n    level: 'info',\n    handleExceptions: true,\n    json: true,\n    colorize: true,\n    prettyPrint: true,\n    humanReadableUnhandledException: true\n  }\n};\nconst logger = new winston.Logger({\n  transports: [\n  //  new winston.transports.File(options.file),\n    new winston\n      .transports\n      .Console(options.console),\n  ],\n  exceptionHandlers: [\n    // new winston.transports.File(options.errorLog)\n  ],\n  exitOnError: false, // do not exit on handled exceptions\n});\n\n// create a stream object with a 'write' function that will be used by `morgan`\nlogger.stream = {\n  write(message, encoding) {\n    logger.info(message);\n  }\n};\nexport default logger;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/helper/responseTemplate.ts",
    "content": "/* istanbul ignore file */\nconst data: any = {\n  general(data) {\n    return data;\n  },\n  successMessage(message) {\n    return {\n      success: true,\n      message\n    };\n  },\n  success(data, message) {\n    return {\n      success: true,\n      message,\n      data\n    };\n  },\n  error(message, err, code= null) {\n    return {\n      success: false,\n      message: message || 'some error occurred',\n      error: err || 'error occurred on server, please try again after some time.'\n    };\n  },\n  emptyContent() {\n    return this.general({\n      message: 'empty content found',\n      description: 'you must provide valid data and it must not be empty.',\n      helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json']\n    });\n  },\n  invalidContentType() {\n    return this.general({\n      message: 'invalid content type',\n      description: 'you must specify content type and it must be application/json',\n      helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type']\n    });\n  },\n  BadRequestFromJoi(err) {\n    return this.error(\n      err.message,\n      err.error\n    );\n  },\n  userAlreadyExist(err) {\n    return this.general({\n      success: false,\n      message: 'user already registered in System',\n      description: 'user already registered in System'\n    });\n  },\n  userdoesNotExist(err) {\n    return this.general({\n      success: false,\n      message: err.message || 'user not registered in system',\n      description: 'user account does not exist in system'\n    });\n  },\n  commonAuthUserDataError() {\n    return this.error(\n       'Authentication error',\n       'token verification failed, Please try again'\n    );\n  },\n  tokenRequiredAuthError() {\n    return this.error(\n      'Authentication error, Token is required in Header',\n      'token verification failed, Please try again'\n    );\n  },\n};\nexport default data;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/helper/twillo.ts",
    "content": "const twilioConfig = global['configuration'].twilio;\n// import twilio from 'twilio';\n\nconst twillo = require('twilio')\nconst client = new twillo(twilioConfig.sid, twilioConfig.token);\n\nlet TwilioHelper = {\n\n  phone_verification(phone_number, code, callback) {\n    client.sendMessage({\n      to: phone_number,\n      from: twilioConfig.phone,\n      body: `Hello from Bal Bla e-Commerce-Hub\\nYour verification code is ${code}`,\n    }, (err, message) => {\n      callback(message);\n    });\n  },\n  password_reset_notification(phone) {\n    client.sendMessage({\n      to: phone,\n      from: twilioConfig.phone,\n      body: `Bla Bla\\nYour password has been successfully reset.`,\n    }, (err, message) => {\n      // \n    });\n  },\n\n  default_notification(phone, message) {\n    console.log(client);\n    client.sendMessage({\n      to: phone,\n      from: twilioConfig.phone,\n      body: `e-Commerce-Hub-TM\\n${message}`,\n    }, (err, message) => {\n      // \n    });\n  }\n}\nexport default TwilioHelper;\n\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/lib/logger.ts",
    "content": "const winston = require('winston');\nconst moment = require('moment');\n\n// define the custom settings for each transport (file, console)\nconst options = {\n  console: {\n    level: 'info',\n    handleExceptions: true,\n    json: true,\n    colorize: true,\n    timestamp() {\n      return moment\n        .utc()\n        .format();\n    },\n    prettyPrint: true,\n    humanReadableUnhandledException: true\n  }\n};\nconst logger = new winston.Logger({\n  transports: [\n  //  new winston.transports.File(options.file),\n    new winston\n      .transports\n      .Console(options.console),\n  ],\n  exceptionHandlers: [\n    // new winston.transports.File(options.errorLog)\n  ],\n  exitOnError: false, // do not exit on handled exceptions\n});\n\n// create a stream object with a 'write' function that will be used by `morgan`\nlogger.stream = {\n  write(message, encoding) {\n    logger.info(message);\n  }\n};\nexport default logger;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/lib/mongoose.ts",
    "content": "/* eslint func-names:0 */\nconst mongoose = require('mongoose');\nmongoose.promises = require('bluebird');\nconst { url } = global['configuration'].mongo;\nconst MongoConnect = function () {\n  const db = mongoose.connect(url, { useNewUrlParser: true }, (error) => {\n    if (error) {\n      console.log(`Mongoose default connection error: ${error}`);\n    } else {\n      console.log('mongo Connected :)');\n    }\n  });\n  mongoose.connection.on('connected', () => {\n    console.log(`Mongoose default connection open to ${url}`);\n  });\n\n  // If the connection throws an error\n  mongoose.connection.on('error', (err) => {\n    console.log(`Mongoose default connection error: ${err}`);\n  });\n\n  // When the connection is disconnected\n  mongoose.connection.on('disconnected', () => {\n    console.log('Mongoose default connection disconnected');\n  });\n\n  // If the Node process ends, close the Mongoose connection\n  process.on('SIGINT', () => {\n    mongoose.connection.close(() => {\n      console.log('Mongoose default connection disconnected through app termination');\n      process.exit(0);\n    });\n  });\n  return db;\n};\n\nexport default MongoConnect;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/lib/requestValidator.ts",
    "content": "const Joi = require('joi');\n\nconst validation = {\n  loginUser : {\n    body : {\n    email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n    password: Joi.string().min(8).max(50).required()\n    }\n  },\n  createUser: {\n    body: {\n      username: Joi.string().min(4).max(50).required(),\n      password: Joi.string().min(8).max(50).required(),\n      email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n      verify_password: Joi.string().min(6).max(50).required()\n    },\n  },\n  resetPassword: {\n    body: {\n      email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n    }\n  }\n};\nexport default validation\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/middleware/authMiddleware.ts",
    "content": "const jwt = require(\"jsonwebtoken\");\nimport responseTemplate from '../helper/responseTemplate';\nimport User from '../models/user';\nconst validation: any = {\n  validateToken(req, res, next) {\n    // validatr token here is its valid here\n    const token = req.headers.authorization;\n    if (token) {\n      jwt.verify(token, \"secretkey\", (err, data) => {\n        if (err) {\n          res.status(403).json(responseTemplate.commonAuthUserDataError());\n        } else {\n          User.findById(data.id, (error, user) => {\n            if(error){\n              res.status(403).json(responseTemplate.commonAuthUserDataError());\n            } \n            user.hasPassword = user.password ? true : false;\n            req.user = user;\n            next();\n          })\n        }\n      });\n    } else {\n      res.status(403).json(responseTemplate.tokenRequiredAuthError());\n    }\n  }\n};\n\nexport default validation;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/middleware/requestValidator.ts",
    "content": "\nmodule.exports = {\n  validatePayload(req, res, next) {\n    // validatr token here is its valid here\n    const token = req.body;\n    if ((req.method === 'POST' || req.method === 'PUT') && req.body !== null) {\n      next();\n    }\n    res.status(403).json({ message: 'payload is required for HTTP Post & Put ' });\n  }\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/models/plugin/plugin.ts",
    "content": "const datePlugin  = function timestamp(schema) {\n  // Add the two fields to the schema\n  schema.add({ \n    createdAt: Date,\n    updatedAt: Date\n  })\n\n  // Create a pre-save hook\n  schema.pre('save', function (next) {\n    let now = Date.now()\n    \n   \n    this.updatedAt = now\n    // Set a value for createdAt only if it is null\n    if (!this.createdAt) {\n      this.createdAt = now\n    }\n   // Call the next function in the pre-save chain\n   next()    \n  })\n}\n\nexport default datePlugin;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/models/user.ts",
    "content": "const mongoose = require('mongoose');\nconst bcrypt = require('bcrypt-nodejs');\nimport helper from '../helper/bcrypt';\nconst { Schema } = mongoose;\nimport timestampPlugin from './plugin/plugin';\nimport Helper from '../../app/helper/bcrypt';\nconst userSchema = new Schema({\n  provider: {\n    type: String\n  },\n  username: {\n    type: String\n  },\n  password: { type: String },\n  email: {\n    index: { unique: true },\n    type: String\n  },\n  address: {\n    type: String\n  },\n  meta: mongoose.Schema.Types.Mixed,\n  picture : mongoose.Schema.Types.Mixed,\n  /*\n  reviews : [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'Review'\n  }],\n  booking :  [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'Booking'\n  }],\n  vehicles: [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'Vehicle'\n  }], */\n  uuid: {\n    type: String\n  },\n  type: {\n    type: String,\n    default: 1\n  },\n  status: {\n    type: String,\n    default: 1\n  },\n  profile_picture: mongoose.Schema.Types.Mixed,\n  phone: String,\n  email_verified: Boolean,\n  phone_verified: Boolean,\n  social: mongoose.Schema.Types.Mixed,\n  documents: [mongoose.Schema.Types.Mixed],\n  gender: Number, // 1: Male, 2: Female, 3: Unspecified\n},{ toJSON: { virtuals: true } });\n\nuserSchema.set('toObject', { virtuals: true });\nuserSchema.set('toJSON', { virtuals: true });\nuserSchema.plugin(timestampPlugin)\n\nconst User = mongoose.model('User', userSchema);\n\nexport default User;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/defaultRoutes.ts",
    "content": "import * as express from \"express\";\nconst router = express.Router();\n\nimport { Router } from \"express\";\n\n\n\nexport class DefaultRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n  }\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\n  public sayHello(req, res) {\n    res.status(200).json({ success: true, message: 'i am up and running .. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️' });\n  };\n\n  init() {\n    this.router.get(\"/\", this.sayHello);\n  }\n}\n\n\n// Create the HeroRouter, and export its configured Express.Router\nconst defaultRouter = new DefaultRouter();\ndefaultRouter.init();\n\nexport default defaultRouter.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/provider/Facebook.ts",
    "content": "\nimport * as passport from 'passport';\nconst FacebookStrategy = require('passport-facebook');\nimport userController from '../../controller/UserController';\n/* eslint no-underscore-dangle: 0 */\n\npassport.use(new FacebookStrategy(\n  {\n    clientID: global.configuration.facebook.client_id,\n    clientSecret: global.configuration.facebook.client_secret,\n    callbackURL: global.configuration.facebook.callback_url,\n    profileFields: ['id', 'displayName', 'photos', 'email'],\n    passReqToCallback: true,\n  },\n  (req, accessToken, refreshToken, profile, done) => {\n    const data = profile._json;\n    if (!data.email) {\n      data.email = 'ramnivas.yadav@srijan.net';\n    }\n    userController.registerSocial({\n      provider: 'facebook',\n      name: data.name,\n      email: data.email,\n      phone: '5436785432',\n      meta: {\n        provider: 'facebook',\n        id: profile.id,\n        token: accessToken,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n\n  }\n));\n\nconst FacebookRoutes = {\n  authenticate: () => passport.authenticate('facebook', { scope: ['email', 'public_profile', 'user_location'] }),\n  callback: () => passport.authenticate('facebook', {\n    failureRedirect: '/auth/failed'\n  })\n\n};\n\nexport default  FacebookRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/provider/Google.ts",
    "content": "\nexport {}\nconst passport = require('passport');\nconst GoogleStrategy = require('passport-google-oauth20').Strategy;\nimport userController from '../../controller/UserController';\n/* eslint no-underscore-dangle: 0 */\n\npassport.use(new GoogleStrategy(\n  {\n    clientID: global.configuration.google.client_id,\n    clientSecret: global.configuration.google.client_secret,\n    callbackURL: `${global.configuration.url.API}/auth/callback/google`,\n    profileFields: ['id', 'displayName', 'photos', 'email']\n  },\n  (accessToken, refreshToken, profile, done) => {\n    const data = profile._json;\n    console.log(data);\n    userController.registerSocial({\n      provider: 'google',\n      username: data.displayName,\n      email: data.emails[0].value,\n      phone: '5436785432',\n      picture : data.image.url,\n      meta: {\n        provider: 'google',\n        id: data.id,\n        token: accessToken,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n  }\n));\n\n\nconst GoogleRoutes = {\n  authenticate: () => passport.authenticate('google', { scope: ['profile', 'email'] }),\n\n  callback: () => passport.authenticate('google', { failureRedirect: '/login' }),\n  function(req, res) {\n    // Successful authentication, redirect home.\n    res.redirect('/');\n  }\n};\n\n\nexport default GoogleRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/provider/Linkedin.ts",
    "content": "export {}\nconst passport = require('passport');\nconst LinkedInStrategy = require('passport-linkedin');\nimport userController from '../../controller/UserController';\n/* eslint no-underscore-dangle: 0 */\npassport.use(new LinkedInStrategy(\n  {\n    consumerKey: global.configuration.linkedin.client_id,\n    consumerSecret: global.configuration.linkedin.client_secret,\n    callbackURL: global.configuration.linkedin.callback_url,\n    profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline']\n  },\n  ((token, tokenSecret, profile, done) => {\n    console.log(profile);\n    const data = profile._json;\n    userController.registerSocial({\n      provider: 'linkedin',\n      name: `${data.firstName} ${data.lastName}`,\n      email: data.emailAddress,\n      mobno: '5436785432',\n      meta: {\n        provider: 'linkedin',\n        id: data.id,\n        token,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n  })\n));\n\nconst LinkedinRoutes = {\n  authenticate: () => passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }),\n  callback: () => passport.authenticate('linkedin', {\n    failureRedirect: '/auth/failed'\n  })\n\n};\n\nexport default LinkedinRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/provider/Locale.ts",
    "content": "/* eslint prefer-destructuring:0 */\nconst passportModule = require('passport');\nconst LocalStrategy = require('passport-local');\nimport userController from '../../controller/UserController';\nconst User = require('../../models/user');\nconst helper = require('../../helper/bcrypt');\n\n\npassportModule.use(new LocalStrategy(\n  {\n    usernameField: 'email',\n    passwordField: 'password',\n    passReqToCallback: true,\n    session: false\n  },\n  ((req, email, password, done) => {\n    // write code here to find user if it exists in system\n    User.find({ email }, (err, data) => {\n      if (err) {\n        return done(null, null);\n      } else if (data.length === 0) {\n        return done(null, null);\n      }\n      const flag = helper.comparePassword(password, data[0].password);\n      if (!flag) {\n        return done(null, null);\n      }\n      return done(null, data);\n    });\n  })\n));\n\nconst localRoutes = {\n  authenticate() {\n    return passportModule.authenticate('local', { session: false });\n  },\n  authenticate_with_callback: () => passportModule.authenticate('local', {\n    successRedirect: '/auth/success',\n    failureRedirect: '/auth/failed'\n  }),\n};\n\n\nexport default localRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/provider/Twitter.ts",
    "content": "\nconst passport = require('passport');\nconst TwitterStrategy = require('passport-twitter').Strategy;\nimport userController from '../../controller/UserController';\n\n\npassport.use(new TwitterStrategy(\n  {\n    consumerKey: global.configuration.twitter.client_id,\n    consumerSecret: global.configuration.twitter.client_secret,\n    callbackURL: 'http://127.0.0.1:3005/auth/callback/twitter'\n  },\n  (token, tokenSecret, profile, done) => {\n    console.log('data>>>', profile);\n    const data = profile;\n    userController.registerSocial({\n      provider: 'twitter',\n      username: data.username,\n      email: data.email || 'raam.yaadav@gmail.com',\n      mobno: '5436785432',\n      meta: {\n        provider: 'twitter',\n        id: data.id,\n        token,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n  }\n));\n\nconst TwitterRoutes = {\n  authenticate: () => passport.authenticate('twitter'),\n  callback: () => passport.authenticate('twitter', { failureRedirect: '/auth/failed' }),\n  function(req, res) {\n    // Successful authentication, redirect home.\n    res.redirect('/');\n  }\n};\n\n\nexport default  TwitterRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/routes.ts",
    "content": "import * as express from \"express\";\nimport UserController from \"../controller/UserController\";\nconst jwt = require(\"jsonwebtoken\");\n// seralize user Object\nconst url = global['configuration'].url;\nimport LocaleRoute from \"./provider/Locale\";\nimport * as expressJoiValidator from \"express-joi-validator\";\nimport expressJoi from \"../lib/requestValidator\";\n// import FacebookRoutes from \"./provider/Facebook\";\nimport GoogleRoutes from \"./provider/Google\";\n// import LinkedinRoutes from \"./provider/Linkedin\";\nimport Template from \"../helper/responseTemplate\";\n// import TwitterRoute from \"./provider/Twitter\";\nimport * as template from '../helper/responseTemplate';\nconst boom = require(\"express-boom\");\nimport { Router, Request, Response, NextFunction } from \"express\";\nimport helper from '../helper/bcrypt';\nimport ValidAuthTokenMiddleware from '../middleware/authMiddleware';\n\nexport class AuthRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n    this.init();\n  }\n  public register(req: any, res: any) {\n    UserController.registerDefault(req, res, (error, user) => {\n      if (error) {\n        res.status(400).json(Template.userAlreadyExist(error.message));\n      } else {\n        res.json({\n          statusCode: 200,\n          success: true,\n          message: \"user created successfully\",\n          user\n        });\n      }\n    });\n  }\n  public login(req: any, res: any) {\n    UserController.validateUser(req, res, (err, token) => {\n      if (err) {\n        res.status(401).json(Template.userdoesNotExist(err));\n      } else {\n        res.status(200).json({\n          success: true,\n          message: \"success\",\n          token\n        });\n      }\n    });\n  }\n\n  public redirectSocialUser(req, res) {\n    jwt.sign(helper.buildUserToken(req.user), \"secretkey\", (tokError, token) => {\n      if (tokError) {\n        res.boom.badImplementation(tokError);\n      } else {\n        // redirect app to FE app routes with Token\n        console.log('redirecting Now...');\n        res.redirect(helper.authRedirectUrl(`?token=${token}`));\n        /* res.json({\n           statusCode: 200,\n           message: \"success\",\n           token\n         }); */\n      }\n    });\n  }\n  public validate(req: any, res: any) {\n    res.json({\n      statusCode: 200,\n      message: 'validated succsessfully',\n      success: true,\n      user : req.user\n    });\n  }\n\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\n  public resetPassword(req, res) {\n    UserController.resetPassword(req.body.email, (error, success) => {\n      console.log(error)\n      if (error) {\n        res.status(403).json({ success: false, message: error, description: 'error occoured while resetting password' });\n      } else {\n        res.json({\n          statusCode: 200,\n          message: 'success',\n          description: 'if this email is registered with us, you will receive a password reset email soon.',\n        });\n      }\n    });\n  };\n\n  public activateUserAccount(req, res) {\n    UserController.activateUserAccount(req.params.uuid, (error, success) => {\n      if (error) {\n        res.status(403).json({ success: false, message: error, description: 'error occoured while activating user' });\n      } else {\n        res.redirect(url.FE);\n      }\n    });\n  }\n  /**\n   * Take each handler, and attach to one of the Express.Router's\n   * endpoints.\n   */\n  init() {\n    this.router.post(\"/login\", expressJoiValidator(expressJoi.loginUser), this.login);\n    this.router.get(\"/validate\", ValidAuthTokenMiddleware.validateToken, this.validate);\n    this.router.post(\"/register\", expressJoiValidator(expressJoi.createUser), this.register);\n    this.router.post(\"/reset-password\", expressJoiValidator(expressJoi.resetPassword), this.resetPassword);\n    this.router.get(\"/activate/:uuid\", this.activateUserAccount);\n    /**\n     * @api {POST} /auth/login/facebook Social Login\n     * @apiName google\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    /*\n    this.router.get(\"/login/facebook\", FacebookRoutes.authenticate());\n    this.router.get(\n      \"/callback/facebook\",\n      FacebookRoutes.callback(),\n      this.redirectSocialUser\n    );\n   */\n    /**\n     * @api {POST} /auth/login/google Social Login\n     * @apiName google\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    this.router.get(\"/login/google\", GoogleRoutes.authenticate());\n    this.router.get(\n      \"/callback/google\",\n      GoogleRoutes.callback(),\n      this.redirectSocialUser\n    );\n\n    /**\n     * @api {POST} /auth/login/twitter Social Login\n     * @apiName twitter\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    /*this.router.get(\"/login/twitter\", TwitterRoute.authenticate(\"twitter\"));\n    this.router.get(\n      \"/callback/twitter\",\n      TwitterRoute.callback(),\n      this.redirectSocialUser\n    ); */\n\n    /**\n     * @api {POST} /auth/login/linkedin Social Login\n     * @apiName linkedin\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    /*\n    this.router.get(\"/login/likedin\", LinkedinRoutes.authenticate());\n    this.router.get(\"/login/linkedin\", LinkedinRoutes.authenticate());\n    this.router.get(\n      \"/callback/linkedin\",\n      LinkedinRoutes.callback(),\n      this.redirectSocialUser\n    ); */\n  }\n}\n\n// Create the HeroRouter, and export its configured Express.Router\nconst authRoutes = new AuthRouter();\nauthRoutes.init();\n\nexport default authRoutes.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes/userRoutes.ts",
    "content": "import * as express from \"express\";\nconst router = express.Router();\nconst passport = require(\"passport\");\nimport UserController from \"../controller/UserController\";\nconst jwt = require(\"jsonwebtoken\");\n// seralize user Object\nimport  ResponseTemplate from '../global/templates/response';\nimport * as expressJoiValidator from \"express-joi-validator\";\nimport expressJoi from \"../lib/requestValidator\";\nconst boom = require(\"express-boom\");\nimport { Router } from \"express\";\nconst path = require('path')\nconst fs = require('fs');\nconst { uploadpath } = global['configuration']\nconst multer = require('multer');\nimport Helper from '../helper/bcrypt';\n\n\nlet profileStorage = multer.diskStorage({\n\tdestination: function (req, file, cb) {\n\t\tcb( null, path.join( uploadpath.uploaddir, uploadpath.profiledir ) );\n\t},\n\tfilename: function (req, file, cb) {\n\t\tlet extension = Helper.getFileExtension(file.originalname);\n\t\tcb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` );\n\t}\n})\nlet upload = multer({ storage: profileStorage });\n\nlet documentStorage = multer.diskStorage({\n\tdestination: function (req, file, cb) {\n\t\tcb( null, path.join( uploadpath.uploaddir, uploadpath.documentdir ) );\n\t},\n\tfilename: function (req, file, cb) {\n\t\tlet extension = Helper.getFileExtension(file.originalname);\n\t\tcb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` );\n\t}\n})\nlet uploadDocuments = multer({ storage: documentStorage });\n\n\nexport class AuthRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n    this.init();\n  }\n\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\npublic resetPassword(req, res){\n\t\tUserController.resetPassword( req.body.email, ( error, success) => {\n\t\t\tconsole.log(error)\n\t\t\tif ( error ) {\n\t\t\t\tres.status(403).json({success : false, message: error, description: 'error occoured while resetting password' });\n\t\t\t} else {\n\t\t\t\tres.json({\n\t\t\t\t\tstatusCode: 200,\n\t\t\t\t\tmessage: 'success',\n\t\t\t\t\tdescription: 'if this email is registered with us, you will receive a password reset email soon.',\n\t\t\t\t});\n\t\t\t}\n\t\t});\n};\n\npublic updateUser(req, res){\n  UserController.updateUser(req.params.email, req.body ,( error, success) => {\n    if ( error ) {\n      res.status(403).json({success : false, message: error, description: 'error occoured while updating user' });\n    } else {\n      res.json({\n        statusCode: 200,\n        message: 'success',\n        description: 'user updated successfully',\n      });\n    }\n  });\n}\npublic getUserByEmail(req, res){\n  UserController.getUserByEmail(req.params.email ,( error, user) => {\n    if ( error ) {\n      res.status(403).json({success : false, message: error, description: 'error occoured while updating user' });\n    } else {\n      res.json({\n        statusCode: 200,\n        message: 'success',\n        data: user\n      });\n    }\n  });\n}\n\npublic uploadProfilepicture(req, res){\n  UserController.updateUser( req.user.email, { picture: req.file.filename }, ( error, user ) => {\n\t\tif ( error ) {\n\t\t\tres.json( ResponseTemplate.updateErrorOccoured(error) );\n\t\t} else {\n\t\t\tres.json( ResponseTemplate.success(\n\t\t\t\t'your profile picture has been successfully uploaded',\n\t\t\t\t{ picture: Helper.avatarURL(user.picture) })\n\t\t\t);\n\t\t  Helper.deleteFile( 'profile', req.user.picture );\n\t\t}\n\t});\n}\n// upload users profile picture.\npublic uploadDocuments(req, res){\n  let documents:any = {};\n\treq.files.map( (file) => {\n\t\tdocuments.url = file.filename;\n\t\tdocuments.originalname = file.originalname;\n\t\tdocuments.timestamp = new Date();\n\t});\n\n\tUserController.updateUser( req.user.email, { document: documents }, ( error, user ) => {\n\t\tif ( error ) {\n\t\t\tres.json( ResponseTemplate.updateErrorOccoured(error) );\n\t\t} else {\n\t\t\tlet userDocuments = [];\n\t\t\tif ( user.documents ) {\n\t\t\t\tuser.documents.map( (doc) => {\n\t\t\t\t\tuserDocuments.push( Helper.userDocumentURL(doc.url) );\n\t\t\t\t});\n\t\t\t}\n\t\t\tres.json( ResponseTemplate.success(\n\t\t\t\t'host documents have been successfully uploaded',\n\t\t\t\t{ documents: userDocuments })\n\t\t\t);\n\t\t}\n\t});\n}\n\n  /**\n   * Take each handler, and attach to one of the Express.Router's\n   * endpoints.\n   */\n  init() {\n    this.router.get(\"/:email\", this.getUserByEmail);\n    this.router.get(\"/reset-password/:email\",expressJoiValidator(expressJoi.resetPassword),  this.resetPassword);\n    this.router.put(\"/update/:email\", this.updateUser);\n    this.router.post('/upload-profile-picture', upload.single('avatar'), this.uploadProfilepicture);\n    this.router.post('/upload-documents', uploadDocuments.array('documents'), this.uploadDocuments);\n  }\n}\n\n// Create the HeroRouter, and export its configured Express.Router\nconst authRoutes = new AuthRouter();\nauthRoutes.init();\n\nexport default authRoutes.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/routes.ts",
    "content": "/* eslint func-names: [\"error\", \"never\"] */\n/* eslint prefer-destructuring: 0 */\nimport * as express from 'express';\nconst expressRouter= express.Router();\nimport authRoutes from './routes/routes';\nimport userRoutes from './routes/userRoutes';\nimport defaultRoutes from './routes/defaultRoutes';\nimport validAuthTokenMiddleware from './middleware/authMiddleware';\nexpressRouter.use('/', defaultRoutes);\nexpressRouter.use('/uploads/', express.static('uploads'));\nexpressRouter.use('/auth', authRoutes);\nexpressRouter.use('/user',validAuthTokenMiddleware.validateToken, userRoutes);\n\n\n\nexport default expressRouter;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/seed/seedUsers.ts",
    "content": "import User from '../models/user';\n\nconst mongoose = require('mongoose');\n\nconst dbName = 'blabla';\nmongoose.connect(`mongodb://localhost/${dbName}`);\n/* eslint quote-props:0 */\n/* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */\n\nconst users = [\n  {\n    'username': 'tarun',\n    'email': 'tarun@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1222@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun22@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun5@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun6@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'asdfg@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tgfdsa@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },\n  {\n    'username': 'tarun1',\n    'email': 'tarunfgds8@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'asdfcv@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'dekoo@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'hellodemo@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'gmail@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 16.5377266,\n      'lng': 79.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }\n];\n\nUser.collection.drop();\n\nUser.create(users, (err) => {\n  if (err) {\n    throw (err);\n  }\n  console.log(`Created ${users.length} User`);\n  mongoose.connection.close();\n});\n\n\n/* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal:\nnode ./bin/seeds.js. De esta manera se crea la base de datos */\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/seed/seedVehicle.ts",
    "content": "import User from '../models/user';\n\nconst mongoose = require('mongoose');\n\nconst dbName = 'blabla';\nmongoose.connect(`mongodb://localhost/${dbName}`);\n/* eslint quote-props:0 */\n/* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */\n\nconst users = [\n  {\n    'username': 'tarun',\n    'email': 'tarun@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1222@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun22@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun5@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun6@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun7@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun8@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }\n];\n\nUser.collection.drop();\n\nUser.create(users, (err) => {\n  if (err) {\n    throw (err);\n  }\n  console.log(`Created ${users.length} User`);\n  mongoose.connection.close();\n});\n\n\n/* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal:\nnode ./bin/seeds.js. De esta manera se crea la base de datos */\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/transformer/userTransformer.ts",
    "content": "'use strict';\n\nimport _ from 'lodash';\n// import ReviewTransformer from './ReviewTransformer';\n\n\nlet UserTransformer = {\n  xx : (users) =>{\n    if ( Array.isArray(users) ) {\n\t\t\tlet output = [];\n\t\t\tusers.forEach(( user ) => {\n\t\t\t\toutput.push( UserTransformer._transformUsers(user) );\n\t\t\t});\n\t\t\treturn output;\n\t\t}\n\t\telse {\n\t\t\treturn UserTransformer._transformUsers(users);\n\t\t}\n  },\n  transform: (users) => {\n    if (Array.isArray(users)) {\n      let output = [];\n      users.forEach((user) => {\n        output.push(UserTransformer._transform(user));\n      });\n      return output;\n    }\n    else {\n      return UserTransformer._transform(users);\n    }\n  },\n  calculateUsers: (users: any | null) => {\n    if (Array.isArray(users)) {\n      return {\n        Users : users.length ? users.length : 100,\n        vehicles : (users['vehicle'] ) ? users['vehicle'].length : 1000,\n        cities :100\n      }\n    }\n  },\n\n  _transform: (user) => {\n    if (!user) { return {}; }\n    let user_status = (user.status === 1) ? 'active' : 'disabled';\n    return {\n      id: user._id,\n      username : user.username,\n      status: user_status,\n      name: user.name,\n      email: user.email,\n      password: (user.password) ? true : false,\n      phone: user.phone || '',\n      gender: user.gender || '',\n      birthday: user.birthday || '',\n      type: user.type || 1,\n      meta: user.meta || {},\n      social : user.social || [],\n      phone_verified: user.phone_verified ? true : false,\n      email_verified: user.email_verified ? true : false,\n      profile_picture: user.profile_picture ? null : null // will fix later\n    };\n  },\n  transformUsers: ( users ) => {\n\t\tif ( Array.isArray(users) ) {\n\t\t\tlet output = [];\n\t\t\tusers.forEach(( user ) => {\n\t\t\t\toutput.push( UserTransformer._transformUsers(user) );\n\t\t\t});\n\t\t\treturn output;\n\t\t}\n\t\telse {\n\t\t\treturn UserTransformer._transformUsers(users);\n\t\t}\n\t},\n\t_transformUsers: ( user ) => {\n\t\tif ( ! user ) { return {}; }\n    let user_status = ( user.status === '1' ) ? 'active' : 'disabled';\n    const obj:any = {};\n\n\t\treturn Object.assign({}, {\n      id: user._id,\n      username : user.username,\n      status: user_status,\n      name: user.name,\n      email_verified:user.email_verified,\n      phone_verified :user.phone_verified,\n      reviews : user.reviews,\n      vehciles : user.vehciles,\n      email: user.email,\n      date : user.createdAt,\n      type: user.type || 1,\n\t\t}, obj);\n  }\n}\n\nexport default UserTransformer;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/types/global.d.ts",
    "content": "declare namespace NodeJS {\n    export interface Global {\n      configuration: any\n    }\n  }"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/app/types/vendor.d.ts",
    "content": "\ndeclare namespace NodeJS {\n  export interface Global {\n    configuration: any\n  }\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/env.sh",
    "content": "# this environment vairables needs to be set in .env file in applciaiton root directory\n# copy this file as .env and add the appropriate values as per environment.\n# node & mysql\nexport NODE_ENV=\"dev\"\nexport PORT=\"3002\"\nexport MONGOURL=\"mongodb://ms_commerce_mongo/blabla\"\nexport EXPRESS_SESSION_SECRET=\"######################\"\nexport F_CLIENTID=\"###################\"\nexport F_CLIENTSECRET=\"###########################\"\nexport F_CALLBACK=\"/auth/callback/facebook\"\nexport G_CLIENTID=\"@@@@@@@@@@@@@-###############.apps.%%%%%%%%%%%.com\"\nexport G_CLIENTSECRET=\"k##########@@@@@@@@@@@@Ub\"\nexport G_CALLBACK=\"/auth/callback/google\"\nexport L_CLIENTID=\"##################\"\nexport L_CLIENTSECRET=\"############\"\nexport L_CALLBACK=\"/auth/callback/linkedin\"\n\nexport T_CLIENTID=\"##################\"\nexport T_CLIENTSECRET=\"######################\"\nexport T_CALLBACK=\"/auth/callback/twitter\"\nexport FE_URL=\"localhost:3000\"\nexport API_KEY='XX0xxxxx-xX0X0XxXXxXxXXXxX0x'\nexport SMTP_HOST='smtp.mandrillapp.com'\nexport SMTP_PORT='587'\nexport SMTP_USER='#############.net'\nexport SMTP_PASSWORD='##############'\nexport SID='XX0xxxxx-xX0X0XxXXxXxXXXxX0x'\nexport TOKEN='XX0xxxxx-xX0X0XxXXxXxXXXxX0x'\nexport PHONE='+9716156786'\nexport FE='http://localhost:3000'\nexport API='http://localhost:3005'\nexport UPLOAD_DIR='uploads'\nexport PROFILE_PICTURE_DIR='profile'\nexport DOCUMENT_UPLOAD_DIR='documents'\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/express.ts",
    "content": "import router from './app/routes';\nimport * as boom from 'express-boom';\nimport * as expressSession from 'express-session';\nimport  * as cookieParser from 'cookie-parser';\nimport * as passport from 'passport';\nimport * as helmet from 'helmet';\nimport * as cors from 'cors';\nimport * as path from 'path';\nimport * as express from 'express';\nimport * as logger from 'morgan';\nimport * as bodyParser from 'body-parser';\nimport errorHandlers from './app/helper/errorHandler';\n\n// Creates and configures an ExpressJS web server.\nclass App {\n  // ref to Express instance\n  public express: express.Application;\n  //Run configuration methods on the Express instance.\n  constructor() {\n    this.express = express();\n    this.middleware();\n    this.routes();\n  }\n\n  // Configure Express middleware.\n  private middleware(): void {\n    this.express.use(passport.initialize());\n    // required for passport to initlize it\n    this.express.use(expressSession({ secret: 'bla bla' }));\n    this.express.use(passport.session());\n    // initlize session\n    this.express.use(logger('dev'));\n    this.express.disable('x-powered-by');\n    this.express.disable('etag');\n    this.express.use(helmet());\n    this.express.use(boom());\n    this.express.use(helmet.noCache({ noEtag: true })); // set Cache-Control header\n    this.express.use(helmet.noSniff()); // set X-Content-Type-Options header\n    this.express.use(helmet.frameguard()); // set X-Frame-Options header\n    this.express.use(helmet.xssFilter()); // set X-XSS-Protection header\n    // logger logs on console\n    this.express.use(bodyParser.urlencoded({ extended: false, limit: '5mb' })); // parse application/x-www-form-urlencoded\n    this.express.use(bodyParser.json()); // parse application/json\n    // enable CORS\n    this.express.use((req, res, next) => {\n      res.header('Access-Control-Allow-Origin', '*');\n      res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PATCH, OPTIONS');\n      res.header('Access-Control-Allow-Headers', 'Content-Type, api_key, Authorization, Referer');\n      next();\n    });\n    // register all custom Middleware\n    this.express.use(cors({ optionsSuccessStatus: 200 }));\n    this.express.use(cookieParser()); // cookies-parser\n    // manage session by cookies\n    this.express.set('views', path.join(__dirname, 'views')); // setting views\n    this.express.set('view engine', 'hbs');\n    // server side template rendering\n    this.express.use(express.static(path.join(__dirname, 'public')));\n    this.express.use(logger('dev'));\n    this.express.use(bodyParser.json());\n    this.express.use(bodyParser.urlencoded({ extended: false }));\n  }\n\n  // Configure API endpoints.\n  private routes(): void {\n    passport.serializeUser((user, done) => {\n      done(null, user);\n    });\n    passport.deserializeUser((user, done) => {\n      done(null, user);\n    });\n    /* This is just to get up and running, and to make sure what we've got is\n     * working so far. This function will change when we start to add more\n     * API endpoints */\n    this.express.use('/api/v1', router);\n    this.express.use(errorHandlers.internalServerError);\n    this.express.use(errorHandlers.PageNotFound);\n  }\n\n}\n\nexport default new App().express;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/package.json",
    "content": "{\n  \"name\": \"e-commerce-hub\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"cd dist &&  nodemon server.js\",\n    \"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n    \"startdev\": \". ./env.sh  && cd dist &&  nodemon server.js\",\n    \"clean\": \"rm -rf dist\",\n    \"watch\": \"tsc\",\n    \"copy\": \"cp -r uploads dist/\",\n    \"test\": \". ./env.sh  && NODE_ENV=test && mocha \",\n    \"debug\": \". ./env.sh && NODE_ENV=test && cd dist && nodemon --inspect=0.0.0.0:9230 server.js\",\n    \"prestartdev\": \" npm run clean && tsc &&  npm run copy && npm run watch\",\n    \"watchserver\" : \"tsc --watch\",\n    \"dev\": \". ./env.sh && ts-node server.ts\",\n    \"start-tsc\": \". ./env.sh && nodemon ./dist/server.js\",\n    \"buildAndstart\": \". ./env.sh && npm run build && npm run start\"\n  },\n  \"dependencies\": {\n    \"@types/express\": \"^4.11.1\",\n    \"assert\": \"^1.4.1\",\n    \"axios\": \"^0.18.0\",\n    \"bcrypt-nodejs\": \"0.0.3\",\n    \"bluebird\": \"^3.5.3\",\n    \"body-parser\": \"^1.18.3\",\n    \"cookie-parser\": \"^1.4.3\",\n    \"cors\": \"^2.8.5\",\n    \"dotenv\": \"^6.1.0\",\n    \"email-templates\": \"^2.7.1\",\n    \"express\": \"^4.16.4\",\n    \"express-boom\": \"^2.0.0\",\n    \"express-joi-validator\": \"^2.0.0\",\n    \"express-session\": \"^1.15.6\",\n    \"fast-csv\": \"^2.4.1\",\n    \"hbs\": \"^4.0.1\",\n    \"helmet\": \"^3.15.0\",\n    \"joi\": \"^14.1.1\",\n    \"jsonwebtoken\": \"^8.4.0\",\n    \"mocha\": \"^5.2.0\",\n    \"moment\": \"^2.22.2\",\n    \"mongoose\": \"^4.5.9\",\n    \"morgan\": \"^1.9.0\",\n    \"multer\": \"^1.2.0\",\n    \"nodemailer\": \"2.5.0\",\n    \"nodemon\": \"^1.18.6\",\n    \"passport\": \"0.3.2\",\n    \"passport-facebook\": \"2.1.1\",\n    \"passport-google-oauth\": \"1.0.0\",\n    \"passport-google-oauth20\": \"^1.0.0\",\n    \"passport-instagram\": \"1.0.0\",\n    \"passport-linkedin\": \"^1.0.0\",\n    \"passport-local\": \"1.0.0\",\n    \"passport-twitter\": \"1.0.4\",\n    \"pug\": \"2.0.0-beta6\",\n    \"serve-favicon\": \"^2.5.0\",\n    \"ts-lint\": \"^4.5.1\",\n    \"ts-node\": \"^7.0.1\",\n    \"twilio\": \"^2.11.1\",\n    \"typescript\": \"^3.1.6\",\n    \"uuid\": \"^3.3.2\",\n    \"winston\": \"^2.4.2\"\n  },\n  \"devDependencies\": {\n    \"@types/async\": \"^2.0.45\",\n    \"@types/bcrypt-nodejs\": \"^0.0.30\",\n    \"@types/bluebird\": \"^3.5.20\",\n    \"@types/body-parser\": \"^1.16.8\",\n    \"@types/express\": \"^4.11.1\",\n    \"@types/mongoose\": \"^4.7.34\",\n    \"@types/morgan\": \"^1.7.35\",\n    \"@types/node\": \"^9.6.39\",\n    \"@types/nodemailer\": \"^4.3.4\",\n    \"@types/passport\": \"^0.4.3\",\n    \"babel-eslint\": \"^8.0.1\",\n    \"eslint\": \"^4.19.1\",\n    \"eslint-config-airbnb-base\": \"^12.1.0\",\n    \"eslint-plugin-import\": \"^2.9.0\",\n    \"eslint-plugin-node\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/public/javascripts/script.js",
    "content": "document.addEventListener('DOMContentLoaded', () => {\n\n  console.log('IronGenerator JS imported successfully!');\n\n}, false);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/public/style.scss",
    "content": "body {\n  padding: 50px;\n  font: 14px \"Lucida Grande\", Helvetica, Arial, sans-serif;\n}\n\na {\n  color: #00B7FF;\n}\n\n.h1 {\n  font-size: 40px;\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/server.ts",
    "content": "import * as http from 'http';\nimport * as debug from 'debug';\n// After you declare \"app\"\nconst env = process.env.NODE_ENV || 'dev'\nconsole.log(` using ${process.env.NODE_ENV} to run application`);\nglobal.configuration = require(`./app/config/environments/${env}`);\nimport App from './express';\n\nconst port = (process.env.PORT);\nconst logger = require('winston');\nimport mongoose from './app/lib/mongoose';\nmongoose();\n\nconst server = http.createServer(App);\nserver.listen(process.env.PORT);\nserver.on('error', onError);\nserver.on('listening', onListening);\n\n\nfunction onError(error: NodeJS.ErrnoException): void {\n  if (error.syscall !== 'listen') throw error;\n  let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port;\n  switch(error.code) {\n    case 'EACCES':\n      console.error(`${bind} requires elevated privileges`);\n      process.exit(1);\n      break;\n    case 'EADDRINUSE':\n      console.error(`${bind} is already in use`);\n      process.exit(1);\n      break;\n    default:\n      throw error;\n  }\n}\n\nconst gracefulStopServer = function () {\n  // Wait 10 secs for existing connection to close and then exit.\n  setTimeout(() => {\n    logger.info('Shutting down server');\n    process.exit(0);\n  }, 1000);\n};\n\nprocess.on('uncaughtException', (err) => {\n  logger.error(err, 'Uncaught exception');\n  process.exit(1);\n});\n\nprocess.on('unhandledRejection', (reason, promise) => {\n  logger.error({\n    promise,\n    reason\n  }, 'unhandledRejection');\n  process.exit(1);\n});\n\nprocess.on('SIGINT', gracefulStopServer);\nprocess.on('SIGTERM', gracefulStopServer);\n\nfunction onListening(): void {\n  let addr = server.address();\n  let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`;\n  debug(`Listening on ${bind}`);\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"moduleResolution\": \"node\",\n        \"pretty\": true,\n        \"sourceMap\": true,\n        \"target\": \"es6\",\n        \"outDir\": \"./dist\",\n        \"experimentalDecorators\": false,\n        \"emitDecoratorMetadata\": false,\n        \"skipDefaultLibCheck\": false,\n        \"baseUrl\": \"./lib\"\n    },\n    \"files\" : [\n        \"./app/types/vendor.d.ts\"\n    ],\n    \"include\": [\n        \"/**/*.ts\"\n    ],\n    \"exclude\": [\n        \"node_modules\"\n    ]\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/tslint.json",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/uploads/documents/.gitkeep",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Admin/uploads/profile/.gitkeep",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/Dockerfile",
    "content": "FROM node:carbon\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Bundle app source\nCOPY . .\n\n# npm install\nRUN npm install\n\nEXPOSE 3001 9201\nCMD [ \"npm\", \"run\", \"watchserver\" ]\nCMD [ \"npm\", \"run\", \"startdev\" ]\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/README.md",
    "content": "# Application for e-commerce Hub\n\n\nREST API to support application features\n\n  - Express as web framework with Typescript\n  - Passport js for social authentication \n  - Express CORS enabled\n  - boom for error codes & Joi for Validation\n  - Winston for logging and express minitor for monitoring\n  - Mongoose as ODM driver\n  - eslint validation extending airbnb styleguide \n  - git hooks & CI/CD in place\n  - Typescript based compilation tsc compiler\n  - TDD in progress with Mocha\n  - JWT based authentication\n  - multiple Mongoose collection with referencing\n  - payment gateway Integration\n  - Heroku deployment\n  - Mini e-commerce platform \n\n# Cart Application #\n\n\"It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills\n\n```\n# Application Execution\n```javascript\ngit clone  repo\nnpm install\nnpm run startdev\ntsc -- watch\n```\n# Application configuration\n```javascript\nenv.sh need to be added locally \nexport NODE_ENV=\"dev\"\nexport PORT=\"3005\"\nexport MONGOURL=\"mongodb://mongo/hello\"\nexport EXPRESS_SESSION_SECRET=\"************************\"\nexport F_CLIENTID=\"**************\"\nexport F_CLIENTSECRET=\"**********************\"\n```\n\n# Application NPM Script\n```javascript\n\"start\": \"cd dist &&  nodemon server.js\",\n\"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n\"clean\" : \"rm -rf dist\",\n\"copy\" : \"cp -r uploads dist/ && cp -r app/global dist/app/\"\n```\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/config/email.ts",
    "content": "'use strict';\n\nexport default {\n\n  global: {\n    from: 'info@kpilibrary.com',\n  },\n  welcome: {\n    subject: 'Welcome to KPI Library',\n  },\n  password_reset: {\n    subject: 'KPI Library: Reset your password',\n  },\n  event_booked_guest: {\n    subject: 'KPI Library: Your Booking Has Been Confirmed',\n  },\n  event_booked_host: {\n    subject: 'KPI Library: Your Event Has Been Booked',\n  },\n  event_booked_guests_notification: {\n    subject: 'KPI Library: Your Booking Has Been Confirmed',\n  },\n  message_received: {\n    subject: 'KPI Library: New Message Received',\n  },\n  guest_review_email: {\n    subject: 'KPI Library: Event Completed',\n  },\n  alacarte_booked_guest: {\n    subject: 'KPI Library: Alacarte Booking Details',\n  },\n  alacarte_booked_host: {\n    subject: 'KPI Library: Your Alacarte Has Been Booked',\n  }\n}\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/config/environments/dev.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\n\nconfiguration.db = {\n  mysql: {\n    user: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    connectTimeout: 100000\n  },\n  mongo: {\n    host: process.env.MONGO_HOST,\n    port: process.env.MONGO_PORT,\n    uername: process.env.MONGO_USERNAME,\n    password: process.env.MONGO_PASSWORD,\n    database: process.env.MONGO_DATABASE\n  }\n};\n\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\n\nmodule.exports = configuration;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/config/environments/qa.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nmodule.exports = configuration;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/config/environments/test.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nmodule.exports = configuration;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/controller/UserController.ts",
    "content": "const uuidv4 = require('uuid/v4');\nimport User from '../models/user';\ndeclare function require(name: string);\nimport Helper from '../helper/bcrypt';\nconst jwt = require('jsonwebtoken');\nimport helper from '../helper/bcrypt';\nimport mailEvents from '../events/notification';\nimport logger from '../helper/logger';\nimport email from '../helper/email';\n\nconst saltRounds = 10;\nclass userController {\n\n  static getUserByEmail(email, cb) {\n    User.findOne({ 'email': email }, (error, user) => {\n      if (user) {\n        cb(null, user);\n      } else {\n        cb('User does not exist in system', null);\n      }\n    });\n  }\n  static validateUser(req, res, cb) {\n    const { body } = req;\n    User.find({ email: body.email })\n      .then((data) => {\n        if (data && data.length) {\n          const flag = helper.comparePassword(body.password, data[0].password)\n          if (flag) {\n            jwt.sign(helper.buildUserToken(data[0]), 'secretkey', (tokError, token) => {\n              cb(null, token);\n            });\n          } else {\n            cb(new Error('username password does not match'), null);\n          }\n        }\n        else {\n          cb(new Error('no user found with this account email'), null);\n        }\n      }).catch((err)=>{\n        console.log(err);\n        cb(new Error('no user found with this account email'), null);\n      })\n  }\n  static registerDefault(req, res, cb) {\n    const { body } = req;\n    const { location } = req;\n    const hash = helper.generateSaltValue(body.password);\n    return User.find({ email: body.email }).then((user) => {\n      if (user && user.length > 0) {\n        cb(new Error('user already regitsered with us'), null);\n      } else {\n        return User.create(this.buildUser(body, hash, location)\n          , (error, user) => {\n            if (error) {\n              cb(error, null);\n            } else {\n              logger.info('emitting user create event');\n              mailEvents.emit(\"welcome\", user);\n              cb(null, user);\n            }\n          });\n      }\n    });\n  }\n  static buildUser(body, hash = null, location = null) {\n\n    const build = {\n      username: body.username,\n      phone: body.phone,\n      email: body.email,\n      email_verified: false,\n      phone_verified: false,\n      picture: body.picture ? body.picture : null,\n      status: 1,\n      gender: null,\n      documents: [],\n      type: 1,\n      social: body.meta,\n      uuid: uuidv4()\n    }\n    return hash ? Object.assign({}, build, { password: hash }) : build;\n  }\n  static registerSocial(user, callback) {\n      User.findOne({ email: user.email }, (error, existingUser) => {\n        if (existingUser) {\n          callback(null, (existingUser));\n        } else {\n          User.create(this.buildUser(user, null), (err, user) => {\n            if (err) {\n              callback(err, null);\n            } else {\n              callback(null, user);\n              mailEvents.emit(\"welcome\", user);\n            }\n          });\n        }\n      });\n\n  }\n\n  static activateUserAccount(uuid, cb) {\n    User.findOne({ 'uuid': uuid }, (error, foundUser) => {\n      if (foundUser) {\n        foundUser.email_verified = true;\n        foundUser.save(function (err) {\n          if (err) {\n            cb('error occoured while updating record');\n          } else {\n            cb(null, 'done');\n          }\n        });\n      } else {\n        cb('User does not exist in system');\n      }\n    });\n  }\n  static resetPassword(email, callback) {\n    // just generate password and send new password on mail\n    User.findOne({ 'email': email }, (error, foundUser) => {\n      if (foundUser) {\n        let password = Math.random().toString(36).slice(2);\n        const hash = helper.generateSaltValue(password);\n        foundUser.password = hash;\n        foundUser.save(function (err) {\n          if (err) {\n            callback('error occoured while updating record');\n          } else {\n            mailEvents.emit(\"forgotPassword\", foundUser, password);\n            callback(null, 'done');\n          }\n        });\n      } else {\n        callback('User does not exist in system with this email');\n      }\n    });\n  }\n\n  static changeUserRole(req, callback) {\n    const email = req.params.email\n    const body = req.body\n    User.findOne({ 'email': email }, (error, user) => {\n      if (user) {\n        user.type = 2;\n        user.save(function (err, updated_user) {\n          if (err) {\n            callback('error occoured while chaging role');\n          } else {\n            callback(null, updated_user);\n          }\n        });\n      }\n      else {\n        callback('user not found in system', null);\n      }\n    });\n  }\n  static updateUser(email, data, callback) {\n    User.findOne({ 'email': email }, (error, user) => {\n      if (user) {\n        if (data.username) { user.username = data.username; }\n        if (data.gender) { user.gender = data.gender; }\n        if (data.phone) { user.phone = data.phone; }\n        if (data.profile_picture) { user.profile_picture = data.profile_picture; }\n        if (data.password && data.password === data.confirm_password) {\n          const hash = helper.generateSaltValue(data.password);\n          user.password = hash;\n        }\n        if ( data.picture ) { user.picture = Helper.avatarURL(data.picture) }\n\n        if (data.phone_verified) {\n          user.phone_verified = true;\n        }\n        if (data.document) {\n          user.documents.push(data.document);\n        }\n        if (data.meta) {\n          user.meta = {\n            about: data.meta.about || '',\n            fun_fact: data.meta.fun_fact || '',\n            payment: data.meta.payment || '',\n          }\n        }\n        user.save(function (err, updated_user) {\n          if (err) {\n            callback('error occoured while updating record');\n          } else {\n            callback(null, updated_user);\n          }\n        });\n      } else {\n        callback('user not found', null);\n      }\n    });\n  }\n}\n\nexport default userController;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/events/notification.ts",
    "content": "\nimport Email from '../helper/email';\ndeclare function require(name: string);\n\nconst events = require('events');\nconst winston = require('winston');\n// import Twillo from '../helper/twillo';\n\nconst eventEmitter = new events.EventEmitter();\neventEmitter.on('welcome', (user) => {\n  winston.log('info', `sending welcome email to ${user.email}`);\n  // Twillo.default_notification(user.phone, 'welcome')\n  Email.welcome(user);\n});\neventEmitter.on('forgotPassword', (user, password, uuid) => {\n  winston.log('info', `sending forgotPassword email to ${user.email}`);\n  Email.password_reset(user, password);\n  // Twillo.default_notification(user.phone, 'welcome')\n});\n\nexport default eventEmitter;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/global/templates/emails/password-reset-email/html.pug",
    "content": "html(lang='en')\n  head\n    meta(charset='utf-8')\n    meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no')\n    title  password has successfully been reset\n    link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet')\n    link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico')\n    link(rel='stylesheet', href='../assets/styles/style.css', type='text/css')\n  body(data-gr-c-s-loaded='true', style='')\n    .template-wrapper\n    table.body(border='0', cellpadding='0', cellspacing='0')\n      tbody\n        tr\n          td  \n          td.container\n            .content\n              table.main\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              a.template-logo(href='../index.html')\n                                img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='')\n                              p.lead\n                                | Hello #{user.email}, \n                                br\n                                | Your password has successfully been reset\n                              table(border='0', cellpadding='0', cellspacing='0')\n                                tbody\n                                  tr\n                                    td.mt30.mb30(align='center')\n                                      table(border='0', cellpadding='0', cellspacing='0')\n                                        tbody\n                                          tr\n                                            td\n                                              p.user-text\n                                                span  Your new password is #[pre #{password}]\n                                                br\n                                                a.btn-primary(href= login_url) Login \n                              p Thank you\n                              p.mb0\n                                | If you have any problems, please contact me at \n                                a.click-link(href='#') admin@gmail.com\n              table.help-section\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              h2.text-center.mb0 Need more help?\n                              a.support-link(href='#') We're here,ready to here\n              table\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              p\n                                | You received this email beacuse you just signed up for new account. If it look weird\n                                a.default-link(href='#') view it in your browser\n                  .footer\n                    table(border='0', cellpadding='0', cellspacing='0')\n                      tbody\n                        tr\n                          td.content-block\n                            p.text-center\n                              | © 2018 KPI App, Goa India\n                              br\n                              |  If these emails get annoying, please feel to \n                              a(href='#') unsubscribe\n          td  \n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/global/templates/emails/password-reset-email/style.css",
    "content": "@charset \"UTF-8\";\n/* -------------------------------------\n          GLOBAL RESETS\n      ------------------------------------- */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\nimg {\n  border: none;\n  -ms-interpolation-mode: bicubic;\n  max-width: 100%;\n}\n\nbody {\n  background-color: #f6f6f6;\n  font-family: 'Rubik', sans-serif;\n  font-size: 15px;\n  line-height: 28px;\n  -webkit-font-smoothing: antialiased;\n  margin: 0;\n  padding: 0;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n\ntable {\n  border-collapse: separate;\n  mso-table-lspace: 0pt;\n  mso-table-rspace: 0pt;\n  width: 100%;\n}\n\ntable td {\n  font-family: sans-serif;\n  font-size: 14px;\n  vertical-align: top;\n}\n\n/* -------------------------------------\n          BODY & CONTAINER\n      ------------------------------------- */\n\n.body {\n  background-color: #f6f6f6;\n  width: 100%;\n}\n\n.lead {\n  font-size: 18px;\n}\n\n.mt30 {\n  margin-top: 30px;\n  display: block;\n}\n\n.mb30 {\n  margin-bottom: 30px;\n  display: block;\n}\n\n/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  /* makes it centered */\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\n/* This should also be a block element, so that it will fill 100% of the .container */\n\n.content {\n  box-sizing: border-box;\n  display: block;\n  Margin: 0 auto;\n  max-width: 580px;\n  padding: 10px;\n}\n\n/* -------------------------------------\n          HEADER, FOOTER, MAIN\n      ------------------------------------- */\n\n.template-wrapper {\n  background-color: #03A9F4;\n  width: 100%;\n  height: 250px;\n  position: relative;\n}\n\n.click-link {\n  color: #03A9F4;\n  display: inline-block;\n  margin-bottom: 20px;\n}\n\n.help-section {\n  background-color: #ffdcdc;\n  border-radius: 3px;\n  width: 100%;\n  text-align: center;\n}\n\n.mb0 {\n  margin-bottom: 0px;\n}\n\n.support-link {\n  color: #03A9F4;\n  display: inline-block;\n  font-size: 19px;\n  margin-bottom: 0px;\n}\n\n.template-logo {\n  display: block;\n  margin-bottom: 40px;\n  margin: auto;\n}\n\n.user-text {\n  font-size: 18px;\n  font-weight: 500;\n}\n\n.user-text span {\n  font-weight: 600;\n}\n\n.text-secondary {\n  color: #218ef4 !important\n}\n\n.main {\n  background: #ffffff;\n  border-radius: 3px;\n  width: 100%;\n  margin-bottom: 20px;\n}\n\n.wrapper {\n  box-sizing: border-box;\n  padding: 40px 25px;\n}\n\n.content-block {\n  padding-bottom: 10px;\n  padding-top: 10px;\n  line-height: 2;\n}\n\n.footer {\n  clear: both;\n  text-align: center;\n  width: 100%;\n}\n\n.footer td, .footer p, .footer span, .footer a {\n  color: #999999;\n  font-size: 12px;\n  text-align: center;\n}\n\n/* -------------------------------------\n          TYPOGRAPHY\n      ------------------------------------- */\n\nh1, h2, h3, h4 {\n  color: #000000;\n  font-family: sans-serif;\n  font-weight: 400;\n  line-height: 1.4;\n  margin: 0;\n  Margin-bottom: 30px;\n}\n\nh1 {\n  font-size: 35px;\n  font-weight: 300;\n  text-align: center;\n  text-transform: capitalize;\n}\n\np, ul, ol {\n  font-family: sans-serif;\n  font-size: 15px;\n  font-weight: normal;\n  margin: 0;\n  margin-bottom: 15px;\n}\n\np li, ul li, ol li {\n  list-style-position: inside;\n  margin-left: 5px;\n}\n\na {\n  color: #3498db;\n  text-decoration: underline;\n}\n\n/* -------------------------------------\n          BUTTONS\n      ------------------------------------- */\n\n.btn {\n  box-sizing: border-box;\n  width: 100%;\n}\n\n.btn>tbody>tr>td {\n  padding-bottom: 15px;\n}\n\n.btn table {\n  width: auto;\n}\n\n.btn table td {\n  background-color: #ffffff;\n  border-radius: 5px;\n  text-align: center;\n}\n\n.btn a {\n  background-color: #ffffff;\n  border: solid 1px #3498db;\n  border-radius: 5px;\n  box-sizing: border-box;\n  color: #3498db;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 14px;\n  font-weight: bold;\n  margin: 0;\n  padding: 12px 25px;\n  text-decoration: none;\n  text-transform: capitalize;\n}\n\n.btn-primary table td {\n  background-color: #3498db;\n}\n\n.btn-primary a {\n  background-color: #03A9F4;\n  border-color: #03A9F4;\n  color: #ffffff;\n}\n\n.default-link {\n  color: #03A9F4;\n}\n\n.default-link:hover {\n  color: #03A9F4;\n}\n\n/* -------------------------------------\n          OTHER STYLES THAT MIGHT BE USEFUL\n      ------------------------------------- */\n\n.last {\n  margin-bottom: 0;\n}\n\n.first {\n  margin-top: 0;\n}\n\n.align-center {\n  text-align: center;\n}\n\n.align-right {\n  text-align: right;\n}\n\n.align-left {\n  text-align: left;\n}\n\n.clear {\n  clear: both;\n}\n\n.mt0 {\n  margin-top: 0;\n}\n\n.mb0 {\n  margin-bottom: 0;\n}\n\n.preheader {\n  color: transparent;\n  display: none;\n  height: 0;\n  max-height: 0;\n  max-width: 0;\n  opacity: 0;\n  overflow: hidden;\n  visibility: hidden;\n  width: 0;\n}\n\n.powered-by a {\n  text-decoration: none;\n}\n\nhr {\n  border: 0;\n  border-bottom: 1px solid #f6f6f6;\n  Margin: 20px 0;\n}\n\n/* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n\n@media only screen and (max-width: 620px) {\n  table[class=body] h1 {\n    font-size: 28px !important;\n    margin-bottom: 10px !important;\n  }\n  table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a {\n    font-size: 16px !important;\n  }\n  table[class=body] .wrapper, table[class=body] .article {\n    padding: 10px !important;\n  }\n  table[class=body] .content {\n    padding: 0 !important;\n  }\n  table[class=body] .container {\n    padding: 0 !important;\n    width: 100% !important;\n  }\n  table[class=body] .main {\n    border-left-width: 0 !important;\n    border-radius: 0 !important;\n    border-right-width: 0 !important;\n  }\n  table[class=body] .btn table {\n    width: 100% !important;\n  }\n  table[class=body] .btn a {\n    width: 100% !important;\n  }\n  table[class=body] .img-responsive {\n    height: auto !important;\n    max-width: 100% !important;\n    width: auto !important;\n  }\n}\n\n/* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n\n@media all {\n  .ExternalClass {\n    width: 100%;\n  }\n  .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {\n    line-height: 100%;\n  }\n  .apple-link a {\n    color: inherit !important;\n    font-family: inherit !important;\n    font-size: inherit !important;\n    font-weight: inherit !important;\n    line-height: inherit !important;\n    text-decoration: none !important;\n  }\n  .btn-primary table td:hover {\n    background-color: #34495e !important;\n  }\n  .btn-primary a:hover {\n    background-color: #03A9F4 !important;\n    border-color: #03A9F4 !important;\n  }\n}\n.btn-primary {\n  text-decoration: none;\n  color: #FFF;\n  background-color: #03A9F4;\n  border: solid #03A9F4;\n  border-width: 6px 18px;\n  line-height: 2em;\n  /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */\n  /*line-height: 28px;*/\n  font-weight: bold;\n  text-align: center;\n  cursor: pointer;\n  display: inline-block;\n  border-radius: 4px;\n  text-transform: capitalize;\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/global/templates/emails/welcome-email/html.pug",
    "content": "html(lang='en')\n  head\n    meta(charset='utf-8')\n    meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no')\n    title Account Activation email || KPI Library\n    link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet')\n    link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico')\n    link(rel='stylesheet', href='../assets/styles/style.css', type='text/css')\n  body(data-gr-c-s-loaded='true', style='')\n    .template-wrapper\n    table.body(border='0', cellpadding='0', cellspacing='0')\n      tbody\n        tr\n          td  \n          td.container\n            .content\n              table.main\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              a.template-logo(href='../index.html')\n                                img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='')\n                              p.lead\n                                | Hello KPI Library, \n                                br\n                                | Thanks for Signup on KPI App\n                                br\n                                | We have sent User Account Activation Link below\n                              table(border='0', cellpadding='0', cellspacing='0')\n                                tbody\n                                  tr\n                                    td.mt30.mb30(align='center')\n                                      table(border='0', cellpadding='0', cellspacing='0')\n                                        tbody\n                                          tr\n                                            td\n                                              p.user-text\n                                                | Hi,\n                                                span #{user.email},\n                                                br\n                                                br\n                                                a.btn-primary(href= activate_url) Activate  your Account\n                              p Thank you\n                              p.mb0\n                                | If you have any problems, please contact me at \n                                a.click-link(href='#') admin@gmail.com\n              table.help-section\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              h2.text-center.mb0 Need more help?\n                              a.support-link(href='#') We're here,ready to here\n              table\n                tbody\n                  tr\n                    td.wrapper\n                      table(border='0', cellpadding='0', cellspacing='0')\n                        tbody\n                          tr\n                            td\n                              p\n                                | You received this email beacuse you just signed up for new account. If it look weird\n                                a.default-link(href='#') view it in your browser\n                  .footer\n                    table(border='0', cellpadding='0', cellspacing='0')\n                      tbody\n                        tr\n                          td.content-block\n                            p.text-center\n                              | © 2018 KPI App, Goa India\n                              br\n                              |  If these emails get annoying, please feel to \n                              a(href='#') unsubscribe\n          td  \n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/global/templates/emails/welcome-email/style.css",
    "content": "@charset \"UTF-8\";\n/* -------------------------------------\n          GLOBAL RESETS\n      ------------------------------------- */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\nimg {\n  border: none;\n  -ms-interpolation-mode: bicubic;\n  max-width: 100%;\n}\n\nbody {\n  background-color: #f6f6f6;\n  font-family: 'Rubik', sans-serif;\n  font-size: 15px;\n  line-height: 28px;\n  -webkit-font-smoothing: antialiased;\n  margin: 0;\n  padding: 0;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n\ntable {\n  border-collapse: separate;\n  mso-table-lspace: 0pt;\n  mso-table-rspace: 0pt;\n  width: 100%;\n}\n\ntable td {\n  font-family: sans-serif;\n  font-size: 14px;\n  vertical-align: top;\n}\n\n/* -------------------------------------\n          BODY & CONTAINER\n      ------------------------------------- */\n\n.body {\n  background-color: #f6f6f6;\n  width: 100%;\n}\n\n.lead {\n  font-size: 18px;\n}\n\n.mt30 {\n  margin-top: 30px;\n  display: block;\n}\n\n.mb30 {\n  margin-bottom: 30px;\n  display: block;\n}\n\n/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */\n\n.container {\n  display: block;\n  Margin: 0 auto !important;\n  /* makes it centered */\n  max-width: 580px;\n  padding: 10px;\n  width: 580px;\n  position: relative;\n  bottom: 140px;\n}\n\n/* This should also be a block element, so that it will fill 100% of the .container */\n\n.content {\n  box-sizing: border-box;\n  display: block;\n  Margin: 0 auto;\n  max-width: 580px;\n  padding: 10px;\n}\n\n/* -------------------------------------\n          HEADER, FOOTER, MAIN\n      ------------------------------------- */\n\n.template-wrapper {\n  background-color: #03A9F4;\n  width: 100%;\n  height: 250px;\n  position: relative;\n}\n\n.click-link {\n  color: #03A9F4;\n  display: inline-block;\n  margin-bottom: 20px;\n}\n\n.help-section {\n  background-color: #ffdcdc;\n  border-radius: 3px;\n  width: 100%;\n  text-align: center;\n}\n\n.mb0 {\n  margin-bottom: 0px;\n}\n\n.support-link {\n  color: #03A9F4;\n  display: inline-block;\n  font-size: 19px;\n  margin-bottom: 0px;\n}\n\n.template-logo {\n  display: block;\n  margin-bottom: 40px;\n  margin: auto;\n}\n\n.user-text {\n  font-size: 18px;\n  font-weight: 500;\n}\n\n.user-text span {\n  font-weight: 600;\n}\n\n.text-secondary {\n  color: #218ef4 !important\n}\n\n.main {\n  background: #ffffff;\n  border-radius: 3px;\n  width: 100%;\n  margin-bottom: 20px;\n}\n\n.wrapper {\n  box-sizing: border-box;\n  padding: 40px 25px;\n}\n\n.content-block {\n  padding-bottom: 10px;\n  padding-top: 10px;\n  line-height: 2;\n}\n\n.footer {\n  clear: both;\n  text-align: center;\n  width: 100%;\n}\n\n.footer td, .footer p, .footer span, .footer a {\n  color: #999999;\n  font-size: 12px;\n  text-align: center;\n}\n\n/* -------------------------------------\n          TYPOGRAPHY\n      ------------------------------------- */\n\nh1, h2, h3, h4 {\n  color: #000000;\n  font-family: sans-serif;\n  font-weight: 400;\n  line-height: 1.4;\n  margin: 0;\n  Margin-bottom: 30px;\n}\n\nh1 {\n  font-size: 35px;\n  font-weight: 300;\n  text-align: center;\n  text-transform: capitalize;\n}\n\np, ul, ol {\n  font-family: sans-serif;\n  font-size: 15px;\n  font-weight: normal;\n  margin: 0;\n  margin-bottom: 15px;\n}\n\np li, ul li, ol li {\n  list-style-position: inside;\n  margin-left: 5px;\n}\n\na {\n  color: #3498db;\n  text-decoration: underline;\n}\n\n/* -------------------------------------\n          BUTTONS\n      ------------------------------------- */\n\n.btn {\n  box-sizing: border-box;\n  width: 100%;\n}\n\n.btn>tbody>tr>td {\n  padding-bottom: 15px;\n}\n\n.btn table {\n  width: auto;\n}\n\n.btn table td {\n  background-color: #ffffff;\n  border-radius: 5px;\n  text-align: center;\n}\n\n.btn a {\n  background-color: #ffffff;\n  border: solid 1px #3498db;\n  border-radius: 5px;\n  box-sizing: border-box;\n  color: #3498db;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 14px;\n  font-weight: bold;\n  margin: 0;\n  padding: 12px 25px;\n  text-decoration: none;\n  text-transform: capitalize;\n}\n\n.btn-primary table td {\n  background-color: #3498db;\n}\n\n.btn-primary a {\n  background-color: #3498db;\n  border-color: #3498db;\n  color: #ffffff;\n}\n\n.default-link {\n  color: #3498db;\n}\n\n.default-link:hover {\n  color: #3498db;\n}\n\n/* -------------------------------------\n          OTHER STYLES THAT MIGHT BE USEFUL\n      ------------------------------------- */\n\n.last {\n  margin-bottom: 0;\n}\n\n.first {\n  margin-top: 0;\n}\n\n.align-center {\n  text-align: center;\n}\n\n.align-right {\n  text-align: right;\n}\n\n.align-left {\n  text-align: left;\n}\n\n.clear {\n  clear: both;\n}\n\n.mt0 {\n  margin-top: 0;\n}\n\n.mb0 {\n  margin-bottom: 0;\n}\n\n.preheader {\n  color: transparent;\n  display: none;\n  height: 0;\n  max-height: 0;\n  max-width: 0;\n  opacity: 0;\n  overflow: hidden;\n  visibility: hidden;\n  width: 0;\n}\n\n.powered-by a {\n  text-decoration: none;\n}\n\nhr {\n  border: 0;\n  border-bottom: 1px solid #f6f6f6;\n  Margin: 20px 0;\n}\n\n/* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n\n@media only screen and (max-width: 620px) {\n  table[class=body] h1 {\n    font-size: 28px !important;\n    margin-bottom: 10px !important;\n  }\n  table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a {\n    font-size: 16px !important;\n  }\n  table[class=body] .wrapper, table[class=body] .article {\n    padding: 10px !important;\n  }\n  table[class=body] .content {\n    padding: 0 !important;\n  }\n  table[class=body] .container {\n    padding: 0 !important;\n    width: 100% !important;\n  }\n  table[class=body] .main {\n    border-left-width: 0 !important;\n    border-radius: 0 !important;\n    border-right-width: 0 !important;\n  }\n  table[class=body] .btn table {\n    width: 100% !important;\n  }\n  table[class=body] .btn a {\n    width: 100% !important;\n  }\n  table[class=body] .img-responsive {\n    height: auto !important;\n    max-width: 100% !important;\n    width: auto !important;\n  }\n}\n\n/* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n\n@media all {\n  .ExternalClass {\n    width: 100%;\n  }\n  .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {\n    line-height: 100%;\n  }\n  .apple-link a {\n    color: inherit !important;\n    font-family: inherit !important;\n    font-size: inherit !important;\n    font-weight: inherit !important;\n    line-height: inherit !important;\n    text-decoration: none !important;\n  }\n  .btn-primary table td:hover {\n    background-color: #34495e !important;\n  }\n  .btn-primary a:hover {\n    background-color: #03A9F4 !important;\n    border-color: #03A9F4 !important;\n  }\n}\n.btn-primary {\n  text-decoration: none;\n  color: #FFF;\n  background-color: #03A9F4;\n  border: solid #03A9F4;\n  border-width: 6px 18px;\n  line-height: 2em;\n  /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */\n  /*line-height: 28px;*/\n  font-weight: bold;\n  text-align: center;\n  cursor: pointer;\n  display: inline-block;\n  border-radius: 4px;\n  text-transform: capitalize;\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/global/templates/response/index.ts",
    "content": "class ResponseTemplate {\n  static general(data) {\n    return data;\n  }\n  static error(code, message, description) {\n    return {\n      statusCode: code || 400,\n      message: message || 'some error occoured',\n      description: description || 'error occoured on server, please try again after some time.'\n    };\n  }\n  static authError() {\n    return this.error(\n      403,\n      'authentication error',\n      'no authentication token provided, please login first and provide the authentication token.'\n    );\n  }\n  static invalidAuthError() {\n    return this.error(\n      403,\n      'authentication error',\n      'invalid Token provided, please login first and provide the authentication token.'\n    );\n  }\n  static emptyContent() {\n    return this.general({\n      statusCode: 402,\n      message: 'empty content found',\n      description: 'you must provide valid data and it must not be empty.',\n      helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json']\n    });\n  }\n  static invalidContentType() {\n    return this.general({\n      statusCode: 400,\n      message: 'invalid content type',\n      description: 'you must specify content type and it must be application/json',\n      helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type']\n    });\n  }\n  static routeNotFound() {\n    return this.error(\n      405,\n      'resource not found',\n      'the resource your tried to access doesn\\'t exist or you dont have permissions to access it.'\n    );\n  }\n  static userNotFound() {\n    return this.error(\n      400,\n      'user not found',\n      \"the user you're looking for doesn't exist or you dont have permissions to access it.\"\n    );\n  }\n  static updateErrorOccoured(error) {\n    return this.error(\n      301,\n      'error occoured',\n      error || 'error occoured while updating your data.'\n    );\n  }\n  static success(description, data=null) {\n\t\treturn {\n\t\t\tstatusCode: 200,\n\t\t\tmessage: 'success',\n\t\t\tdescription: description || 'data successfully saved.',\n\t\t\t...data\n\t\t}\n\t}\n}\n\nexport default ResponseTemplate;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/helper/bcrypt.ts",
    "content": "\nconst bcrypt = require('bcrypt-nodejs');\nconst jwt = require('jsonwebtoken');\nconst {url} = global['configuration']\nconst {uploadpath} = global['configuration']\nconst path = require('path');\nconst fs = require('fs');\nconst helper = {\n  generateSaltValue(password) {\n    const salt = bcrypt.genSaltSync(); // enter number of rounds, default: 10\n    const hash = bcrypt.hashSync(password, salt);\n    return hash;\n  },\n  comparePassword(userPassword, password ) {\n    if (!userPassword.length ||  !( password && password.length > 0) ) {\n      return false;\n    }\n    return bcrypt.compareSync(userPassword, password);\n  },\n  authRedirectUrl( path ) {\n\t\treturn `${url.FE}/#/auth/validate-token/${path}`;\n\t},\n\t\n  buildUserToken(data) {\n    return {\n        email: data.email,\n        id:data._id,\n        username: data.username ? data.username : data.email,\n        hasPassword: data.password ? true : false,\n        type : data.type || 1,\n        picture : data.picture\n    }\n  },\n  resource( path ) {\n\t\treturn `${url.API}${path}`;\n\t},\n  getFileExtension( file ) {\n\t\tlet extensions = file.split('.');\n\t\tif ( extensions.length === 1 ) {\n\t\t\treturn 'jpg';\n\t\t} else {\n\t\t\treturn extensions.pop();\n\t\t}\n\t},\n\tavatarURL( filename ) {\n\t\tif ( filename.includes('://') ) {\n\t\t\treturn filename;\n\t\t}\n\t\treturn this.resource(`/${uploadpath.uploaddir}/${uploadpath.profiledir}/${filename}`);\n\t},\n\tuserDocumentURL( filename ) {\n\t\tif ( filename.includes('://') ) {\n\t\t\treturn filename;\n\t\t}\n\t\treturn this.resource(`/${uploadpath.uploaddir}/${uploadpath.documentdir}/${filename}`);\n\t},\n\trandomString() {\n\t\treturn Math.random().toString(36).substring(2, 7);\n  },\n  deleteFile( type, filename ) {\n\t\tlet location;\n    if ( type === 'profile' ) { location = path.join( uploadpath.uploaddir, uploadpath.profiledir ) }\n\t\telse { location = uploadpath.uploaddir; }\n\t\tif (filename) {\n\t\t\tfs.unlink( path.join( location, filename ), () => {\n\t\t\t\t// in case we need to perform additional operations.\n\t\t\t});\n\t\t}\n\t},\n\tgetPaymentMethodName( method ) {\n\t\tif ( method == 1 ) { return 'PayPal'; }\n\t\telse if ( method == 2 ) { return 'PayPal'; }\n\t\telse if ( method == 3 ) { return 'Instamojo'; }\n\t\telse { return 'Not Specified'; }\n\t},\n\tgetCurrency(currency) {\n\t\tlet allCurrency = {\n\t\t\t1: 'USD',\n\t\t\t2: 'INR',\n\t\t};\n\n\t\tif( allCurrency[currency] ) {\n\t\t\treturn allCurrency[currency];\n\t\t} else {\n\t\t\treturn allCurrency[1];\n\t\t}\n\n\t},\n\tverificationCode() {\n\t\tlet code = Math.floor((Math.random()*999999)+111111);\n\t\treturn code;\n\t}\n};\n\nexport default helper;\n\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/helper/email.ts",
    "content": "const path = require('path');\ndeclare function require(name:string);\n\nconst nodemailer = require('nodemailer');\nconst url = global['configuration'].url;\nconst mailConfig = global['configuration'].email;\n\nimport emailConfig from '../config/email';\nimport { EmailTemplate } from 'email-templates';\n// const Twillo = require('./twillo');\n\n  const transport = nodemailer.createTransport({\n    host: 'smtp.gmail.com',\n    port: 465,\n    secure: true,\n    auth: {\n      // type: 'OAuth2',\n      user: mailConfig.auth.user,\n      pass:  mailConfig.auth.pass\n    },\n  });\nconst Email = {\n  welcome(user) {\n    if (user.email) {\n      let templateDir = path.join('app/global/templates', 'emails', 'welcome-email');\n      let welcomeEmail = new EmailTemplate(templateDir);\n      welcomeEmail.render({ user: user, activate_url: `${url.API}/auth/activate/${user.uuid}` }, (err, result) => {\n        transport.sendMail(\n          {\n            from: emailConfig.global.from,\n            to: user.email,\n            subject: emailConfig.welcome.subject,\n            html: result.html,\n          }, (err, info) => {\n            // some error occoured...\n            console.log(err);\n          }\n        );\n      });\n    }\n  },\n  password_reset(user, password) {\n    if (user.email) {\n      let templateDir = path.join('app/global/templates', 'emails', 'password-reset-email');\n      let passwordResetEmail = new EmailTemplate(templateDir);\n      passwordResetEmail.render({ user: user, login_url: `${url.FE}/#/auth/login`, password: password }, (err, result) => {\n        transport.sendMail(\n          {\n            from: emailConfig.global.from,\n            to: user.email,\n            subject: emailConfig.password_reset.subject,\n            html: result.html,\n          }, (err, info) => {\n            // some error occoured...\n          }\n        );\n      });\n    }\n    if (user.phone_verified) {\n      // Twillo.password_reset_notification(user.phone);\n    }\n\n  },\n};\nexport default Email;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/helper/errorHandler.ts",
    "content": "import * as winston from 'winston';\nimport  ResponseTemplate from './responseTemplate';\n/* eslint class-methods-use-this:0 */\nconst env = process.env.NODE_ENV;\nconst onDevEnv = env === 'dev' || env === 'test' || env === 'local';\nclass errorHandler {\n  public internalServerError(err, req, res, next) {\n    winston.log('info',err);\n    if (err.isBoom) {\n      // Error From  joi express validator\n      const error = {\n        message: err.output.payload.error,\n        error: err.output.payload.message\n      };\n      res.status(400).json(ResponseTemplate.BadRequestFromJoi(error));\n    } else { // internalServerError\n      res.status(500).json({\n        success: false,\n        message: err.message,\n        error: (onDevEnv) ? err.stack : {}\n      });\n    }\n  }\n  public PageNotFound(req, res, err) {\n    res.status(404).json({ message: 'api not found' });\n  }\n}\n\nexport default new errorHandler();\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/helper/logger.ts",
    "content": "const winston = require('winston');\n\n// define the custom settings for each transport (file, console)\nconst options = {\n  console: {\n    level: 'info',\n    handleExceptions: true,\n    json: true,\n    colorize: true,\n    prettyPrint: true,\n    humanReadableUnhandledException: true\n  }\n};\nconst logger = new winston.Logger({\n  transports: [\n  //  new winston.transports.File(options.file),\n    new winston\n      .transports\n      .Console(options.console),\n  ],\n  exceptionHandlers: [\n    // new winston.transports.File(options.errorLog)\n  ],\n  exitOnError: false, // do not exit on handled exceptions\n});\n\n// create a stream object with a 'write' function that will be used by `morgan`\nlogger.stream = {\n  write(message, encoding) {\n    logger.info(message);\n  }\n};\nexport default logger;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/helper/responseTemplate.ts",
    "content": "/* istanbul ignore file */\nconst data: any = {\n  general(data) {\n    return data;\n  },\n  successMessage(message) {\n    return {\n      success: true,\n      message\n    };\n  },\n  success(data, message) {\n    return {\n      success: true,\n      message,\n      data\n    };\n  },\n  error(message, err, code= null) {\n    return {\n      success: false,\n      message: message || 'some error occurred',\n      error: err || 'error occurred on server, please try again after some time.'\n    };\n  },\n  emptyContent() {\n    return this.general({\n      message: 'empty content found',\n      description: 'you must provide valid data and it must not be empty.',\n      helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json']\n    });\n  },\n  invalidContentType() {\n    return this.general({\n      message: 'invalid content type',\n      description: 'you must specify content type and it must be application/json',\n      helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type']\n    });\n  },\n  BadRequestFromJoi(err) {\n    return this.error(\n      err.message,\n      err.error\n    );\n  },\n  userAlreadyExist(err) {\n    return this.general({\n      success: false,\n      message: 'user already registered in System',\n      description: 'user already registered in System'\n    });\n  },\n  userdoesNotExist(err) {\n    return this.general({\n      success: false,\n      message: err.message || 'user not registered in system',\n      description: 'user account does not exist in system'\n    });\n  },\n  commonAuthUserDataError() {\n    return this.error(\n       'Authentication error',\n       'token verification failed, Please try again'\n    );\n  },\n  tokenRequiredAuthError() {\n    return this.error(\n      'Authentication error, Token is required in Header',\n      'token verification failed, Please try again'\n    );\n  },\n};\nexport default data;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/helper/twillo.ts",
    "content": "const twilioConfig = global['configuration'].twilio;\n// import twilio from 'twilio';\n\nconst twillo = require('twilio')\nconst client = new twillo(twilioConfig.sid, twilioConfig.token);\n\nlet TwilioHelper = {\n\n  phone_verification(phone_number, code, callback) {\n    client.sendMessage({\n      to: phone_number,\n      from: twilioConfig.phone,\n      body: `Hello from Bal Bla e-Commerce-Hub\\nYour verification code is ${code}`,\n    }, (err, message) => {\n      callback(message);\n    });\n  },\n  password_reset_notification(phone) {\n    client.sendMessage({\n      to: phone,\n      from: twilioConfig.phone,\n      body: `Bla Bla\\nYour password has been successfully reset.`,\n    }, (err, message) => {\n      // \n    });\n  },\n\n  default_notification(phone, message) {\n    console.log(client);\n    client.sendMessage({\n      to: phone,\n      from: twilioConfig.phone,\n      body: `e-Commerce-Hub-TM\\n${message}`,\n    }, (err, message) => {\n      // \n    });\n  }\n}\nexport default TwilioHelper;\n\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/lib/logger.ts",
    "content": "const winston = require('winston');\nconst moment = require('moment');\n\n// define the custom settings for each transport (file, console)\nconst options = {\n  console: {\n    level: 'info',\n    handleExceptions: true,\n    json: true,\n    colorize: true,\n    timestamp() {\n      return moment\n        .utc()\n        .format();\n    },\n    prettyPrint: true,\n    humanReadableUnhandledException: true\n  }\n};\nconst logger = new winston.Logger({\n  transports: [\n  //  new winston.transports.File(options.file),\n    new winston\n      .transports\n      .Console(options.console),\n  ],\n  exceptionHandlers: [\n    // new winston.transports.File(options.errorLog)\n  ],\n  exitOnError: false, // do not exit on handled exceptions\n});\n\n// create a stream object with a 'write' function that will be used by `morgan`\nlogger.stream = {\n  write(message, encoding) {\n    logger.info(message);\n  }\n};\nexport default logger;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/lib/mongoose.ts",
    "content": "/* eslint no-undef: 0 */\n/* eslint import/no-dynamic-require: 0 */\n\n// Bring Mongoose into the app\nconst env = process.env.NODE_ENV || 'dev';\nconst global1 = require(`../config/environments/${env}`);\nconst mongoConfig = global1['db'].mongo;\nconst mongoose = require('mongoose');\n// Build the connection string\nlet dbURI = `mongodb://${mongoConfig.host}:${mongoConfig.port}/${mongoConfig.database}`;\n//if(env === 'test' || env === 'dev'){\n//  dbURI += '?authSource=admin'\n//}\nconst authOptions = {\n  auth: {\n    user: mongoConfig.uername,\n    password: mongoConfig.password\n  }\n};\nconst connect  = () => {\n// Create the database connection\nmongoose.connect(dbURI, (err) => {\n  if (err) {\n    console.log(err.message);\n  } else {\n    console.log('Mongoose Connected! to Database');\n  }\n});\n\n\n// CONNECTION EVENTS\n// When successfully connected\nmongoose.connection.on('connected', () => {\n  console.log(`Mongoose default connection open to ${dbURI}`);\n});\n\n// If the connection throws an error\nmongoose.connection.on('error', (err) => {\n  console.log(`Mongoose default connection error: ${err}`);\n});\n\n// When the connection is disconnected\nmongoose.connection.on('disconnected', () => {\n  console.log('Mongoose default connection disconnected');\n}); \n\n// If the Node process ends, close the Mongoose connection\nprocess.on('SIGINT', () => {\n  mongoose.connection.close(() => {\n    console.log('Mongoose default connection disconnected through app termination');\n    process.exit(0);\n  });\n});\n}\n\n\nexport default connect;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/lib/requestValidator.ts",
    "content": "const Joi = require('joi');\n\nconst validation = {\n  loginUser : {\n    body : {\n    email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n    password: Joi.string().min(8).max(50).required()\n    }\n  },\n  createUser: {\n    body: {\n      username: Joi.string().min(4).max(50).required(),\n      password: Joi.string().min(8).max(50).required(),\n      email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n      verify_password: Joi.string().min(6).max(50).required()\n    },\n  },\n  resetPassword: {\n    body: {\n      email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n    }\n  }\n};\nexport default validation\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/middleware/authMiddleware.ts",
    "content": "const jwt = require(\"jsonwebtoken\");\nimport responseTemplate from '../helper/responseTemplate';\nimport User from '../models/user';\nconst validation: any = {\n  validateToken(req, res, next) {\n    // validatr token here is its valid here\n    const token = req.headers.authorization;\n    if (token) {\n      jwt.verify(token, \"secretkey\", (err, data) => {\n        if (err) {\n          res.status(403).json(responseTemplate.commonAuthUserDataError());\n        } else {\n          User.findById(data.id, (error, user) => {\n            if(error){\n              res.status(403).json(responseTemplate.commonAuthUserDataError());\n            } \n            user.hasPassword = user.password ? true : false;\n            req.user = user;\n            next();\n          })\n        }\n      });\n    } else {\n      res.status(403).json(responseTemplate.tokenRequiredAuthError());\n    }\n  }\n};\n\nexport default validation;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/middleware/requestValidator.ts",
    "content": "\nmodule.exports = {\n  validatePayload(req, res, next) {\n    // validatr token here is its valid here\n    const token = req.body;\n    if ((req.method === 'POST' || req.method === 'PUT') && req.body !== null) {\n      next();\n    }\n    res.status(403).json({ message: 'payload is required for HTTP Post & Put ' });\n  }\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/models/plugin/plugin.ts",
    "content": "const datePlugin  = function timestamp(schema) {\n  // Add the two fields to the schema\n  schema.add({ \n    createdAt: Date,\n    updatedAt: Date\n  })\n\n  // Create a pre-save hook\n  schema.pre('save', function (next) {\n    let now = Date.now()\n    \n   \n    this.updatedAt = now\n    // Set a value for createdAt only if it is null\n    if (!this.createdAt) {\n      this.createdAt = now\n    }\n   // Call the next function in the pre-save chain\n   next()    \n  })\n}\n\nexport default datePlugin;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/models/user.ts",
    "content": "const mongoose = require('mongoose');\nconst bcrypt = require('bcrypt-nodejs');\nimport helper from '../helper/bcrypt';\nconst { Schema } = mongoose;\nimport timestampPlugin from './plugin/plugin';\nimport Helper from '../../app/helper/bcrypt';\nconst userSchema = new Schema({\n  provider: {\n    type: String\n  },\n  username: {\n    type: String\n  },\n  password: { type: String },\n  email: {\n    index: { unique: true },\n    type: String\n  },\n  address: {\n    type: String\n  },\n  meta: mongoose.Schema.Types.Mixed,\n  picture : mongoose.Schema.Types.Mixed,\n  /*\n  reviews : [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'Review'\n  }],\n  booking :  [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'Booking'\n  }],\n  vehicles: [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'Vehicle'\n  }], */\n  uuid: {\n    type: String\n  },\n  type: {\n    type: String,\n    default: 1\n  },\n  status: {\n    type: String,\n    default: 1\n  },\n  profile_picture: mongoose.Schema.Types.Mixed,\n  phone: String,\n  email_verified: Boolean,\n  phone_verified: Boolean,\n  social: mongoose.Schema.Types.Mixed,\n  documents: [mongoose.Schema.Types.Mixed],\n  gender: Number, // 1: Male, 2: Female, 3: Unspecified\n},{ toJSON: { virtuals: true } });\n\nuserSchema.set('toObject', { virtuals: true });\nuserSchema.set('toJSON', { virtuals: true });\nuserSchema.plugin(timestampPlugin)\n\nconst User = mongoose.model('User', userSchema);\n\nexport default User;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/defaultRoutes.ts",
    "content": "import * as express from \"express\";\nconst router = express.Router();\n\nimport { Router } from \"express\";\n\n\n\nexport class DefaultRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n  }\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\n  public sayHello(req, res) {\n    res.status(200).json({ success: true, message: 'i am up and running node + mongo .. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️' });\n  };\n\n  init() {\n    this.router.get(\"/\", this.sayHello);\n  }\n}\n\n\n// Create the HeroRouter, and export its configured Express.Router\nconst defaultRouter = new DefaultRouter();\ndefaultRouter.init();\n\nexport default defaultRouter.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/provider/Facebook.ts",
    "content": "\nimport * as passport from 'passport';\nconst FacebookStrategy = require('passport-facebook');\nimport userController from '../../controller/UserController';\n/* eslint no-underscore-dangle: 0 */\n\npassport.use(new FacebookStrategy(\n  {\n    clientID: global.configuration.facebook.client_id,\n    clientSecret: global.configuration.facebook.client_secret,\n    callbackURL: global.configuration.facebook.callback_url,\n    profileFields: ['id', 'displayName', 'photos', 'email'],\n    passReqToCallback: true,\n  },\n  (req, accessToken, refreshToken, profile, done) => {\n    const data = profile._json;\n    if (!data.email) {\n      data.email = 'ramnivas.yadav@srijan.net';\n    }\n    userController.registerSocial({\n      provider: 'facebook',\n      name: data.name,\n      email: data.email,\n      phone: '5436785432',\n      meta: {\n        provider: 'facebook',\n        id: profile.id,\n        token: accessToken,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n\n  }\n));\n\nconst FacebookRoutes = {\n  authenticate: () => passport.authenticate('facebook', { scope: ['email', 'public_profile', 'user_location'] }),\n  callback: () => passport.authenticate('facebook', {\n    failureRedirect: '/auth/failed'\n  })\n\n};\n\nexport default  FacebookRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/provider/Google.ts",
    "content": "\nexport {}\nconst passport = require('passport');\nconst GoogleStrategy = require('passport-google-oauth20').Strategy;\nimport userController from '../../controller/UserController';\n/* eslint no-underscore-dangle: 0 */\n\npassport.use(new GoogleStrategy(\n  {\n    clientID: global.configuration.google.client_id,\n    clientSecret: global.configuration.google.client_secret,\n    callbackURL: `${global.configuration.url.API}/auth/callback/google`,\n    profileFields: ['id', 'displayName', 'photos', 'email']\n  },\n  (accessToken, refreshToken, profile, done) => {\n    const data = profile._json;\n    console.log(data);\n    userController.registerSocial({\n      provider: 'google',\n      username: data.displayName,\n      email: data.emails[0].value,\n      phone: '5436785432',\n      picture : data.image.url,\n      meta: {\n        provider: 'google',\n        id: data.id,\n        token: accessToken,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n  }\n));\n\n\nconst GoogleRoutes = {\n  authenticate: () => passport.authenticate('google', { scope: ['profile', 'email'] }),\n\n  callback: () => passport.authenticate('google', { failureRedirect: '/login' }),\n  function(req, res) {\n    // Successful authentication, redirect home.\n    res.redirect('/');\n  }\n};\n\n\nexport default GoogleRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/provider/Linkedin.ts",
    "content": "export {}\nconst passport = require('passport');\nconst LinkedInStrategy = require('passport-linkedin');\nimport userController from '../../controller/UserController';\n/* eslint no-underscore-dangle: 0 */\npassport.use(new LinkedInStrategy(\n  {\n    consumerKey: global.configuration.linkedin.client_id,\n    consumerSecret: global.configuration.linkedin.client_secret,\n    callbackURL: global.configuration.linkedin.callback_url,\n    profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline']\n  },\n  ((token, tokenSecret, profile, done) => {\n    console.log(profile);\n    const data = profile._json;\n    userController.registerSocial({\n      provider: 'linkedin',\n      name: `${data.firstName} ${data.lastName}`,\n      email: data.emailAddress,\n      mobno: '5436785432',\n      meta: {\n        provider: 'linkedin',\n        id: data.id,\n        token,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n  })\n));\n\nconst LinkedinRoutes = {\n  authenticate: () => passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }),\n  callback: () => passport.authenticate('linkedin', {\n    failureRedirect: '/auth/failed'\n  })\n\n};\n\nexport default LinkedinRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/provider/Locale.ts",
    "content": "/* eslint prefer-destructuring:0 */\nconst passportModule = require('passport');\nconst LocalStrategy = require('passport-local');\nimport userController from '../../controller/UserController';\nconst User = require('../../models/user');\nconst helper = require('../../helper/bcrypt');\n\n\npassportModule.use(new LocalStrategy(\n  {\n    usernameField: 'email',\n    passwordField: 'password',\n    passReqToCallback: true,\n    session: false\n  },\n  ((req, email, password, done) => {\n    // write code here to find user if it exists in system\n    User.find({ email }, (err, data) => {\n      if (err) {\n        return done(null, null);\n      } else if (data.length === 0) {\n        return done(null, null);\n      }\n      const flag = helper.comparePassword(password, data[0].password);\n      if (!flag) {\n        return done(null, null);\n      }\n      return done(null, data);\n    });\n  })\n));\n\nconst localRoutes = {\n  authenticate() {\n    return passportModule.authenticate('local', { session: false });\n  },\n  authenticate_with_callback: () => passportModule.authenticate('local', {\n    successRedirect: '/auth/success',\n    failureRedirect: '/auth/failed'\n  }),\n};\n\n\nexport default localRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/provider/Twitter.ts",
    "content": "\nconst passport = require('passport');\nconst TwitterStrategy = require('passport-twitter').Strategy;\nimport userController from '../../controller/UserController';\n\n\npassport.use(new TwitterStrategy(\n  {\n    consumerKey: global.configuration.twitter.client_id,\n    consumerSecret: global.configuration.twitter.client_secret,\n    callbackURL: 'http://127.0.0.1:3005/auth/callback/twitter'\n  },\n  (token, tokenSecret, profile, done) => {\n    console.log('data>>>', profile);\n    const data = profile;\n    userController.registerSocial({\n      provider: 'twitter',\n      username: data.username,\n      email: data.email || 'raam.yaadav@gmail.com',\n      mobno: '5436785432',\n      meta: {\n        provider: 'twitter',\n        id: data.id,\n        token,\n      }\n    }, (err, profileData) => {\n      if (err) {\n        done(err, null);\n      }\n      done(null, profileData);\n    });\n  }\n));\n\nconst TwitterRoutes = {\n  authenticate: () => passport.authenticate('twitter'),\n  callback: () => passport.authenticate('twitter', { failureRedirect: '/auth/failed' }),\n  function(req, res) {\n    // Successful authentication, redirect home.\n    res.redirect('/');\n  }\n};\n\n\nexport default  TwitterRoutes;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/routes.ts",
    "content": "import * as express from \"express\";\nimport UserController from \"../controller/UserController\";\nconst jwt = require(\"jsonwebtoken\");\n// seralize user Object\nconst url = global['configuration'].url;\nimport LocaleRoute from \"./provider/Locale\";\nimport * as expressJoiValidator from \"express-joi-validator\";\nimport expressJoi from \"../lib/requestValidator\";\n// import FacebookRoutes from \"./provider/Facebook\";\nimport GoogleRoutes from \"./provider/Google\";\n// import LinkedinRoutes from \"./provider/Linkedin\";\nimport Template from \"../helper/responseTemplate\";\n// import TwitterRoute from \"./provider/Twitter\";\nimport * as template from '../helper/responseTemplate';\nconst boom = require(\"express-boom\");\nimport { Router, Request, Response, NextFunction } from \"express\";\nimport helper from '../helper/bcrypt';\nimport ValidAuthTokenMiddleware from '../middleware/authMiddleware';\n\nexport class AuthRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n    this.init();\n  }\n  public register(req: any, res: any) {\n    UserController.registerDefault(req, res, (error, user) => {\n      if (error) {\n        res.status(400).json(Template.userAlreadyExist(error.message));\n      } else {\n        res.json({\n          statusCode: 200,\n          success: true,\n          message: \"user created successfully\",\n          user\n        });\n      }\n    });\n  }\n  public login(req: any, res: any) {\n    UserController.validateUser(req, res, (err, token) => {\n      if (err) {\n        res.status(401).json(Template.userdoesNotExist(err));\n      } else {\n        res.status(200).json({\n          success: true,\n          message: \"success\",\n          token\n        });\n      }\n    });\n  }\n\n  public redirectSocialUser(req, res) {\n    jwt.sign(helper.buildUserToken(req.user), \"secretkey\", (tokError, token) => {\n      if (tokError) {\n        res.boom.badImplementation(tokError);\n      } else {\n        // redirect app to FE app routes with Token\n        console.log('redirecting Now...');\n        res.redirect(helper.authRedirectUrl(`?token=${token}`));\n        /* res.json({\n           statusCode: 200,\n           message: \"success\",\n           token\n         }); */\n      }\n    });\n  }\n  public validate(req: any, res: any) {\n    res.json({\n      statusCode: 200,\n      message: 'validated succsessfully',\n      success: true,\n      user : req.user\n    });\n  }\n\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\n  public resetPassword(req, res) {\n    UserController.resetPassword(req.body.email, (error, success) => {\n      console.log(error)\n      if (error) {\n        res.status(403).json({ success: false, message: error, description: 'error occoured while resetting password' });\n      } else {\n        res.json({\n          statusCode: 200,\n          message: 'success',\n          description: 'if this email is registered with us, you will receive a password reset email soon.',\n        });\n      }\n    });\n  };\n\n  public activateUserAccount(req, res) {\n    UserController.activateUserAccount(req.params.uuid, (error, success) => {\n      if (error) {\n        res.status(403).json({ success: false, message: error, description: 'error occoured while activating user' });\n      } else {\n        res.redirect(url.FE);\n      }\n    });\n  }\n  /**\n   * Take each handler, and attach to one of the Express.Router's\n   * endpoints.\n   */\n  init() {\n    this.router.post(\"/login\", expressJoiValidator(expressJoi.loginUser), this.login);\n    this.router.get(\"/validate\", ValidAuthTokenMiddleware.validateToken, this.validate);\n    this.router.post(\"/register\", expressJoiValidator(expressJoi.createUser), this.register);\n    this.router.post(\"/reset-password\", expressJoiValidator(expressJoi.resetPassword), this.resetPassword);\n    this.router.get(\"/activate/:uuid\", this.activateUserAccount);\n    /**\n     * @api {POST} /auth/login/facebook Social Login\n     * @apiName google\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    /*\n    this.router.get(\"/login/facebook\", FacebookRoutes.authenticate());\n    this.router.get(\n      \"/callback/facebook\",\n      FacebookRoutes.callback(),\n      this.redirectSocialUser\n    );\n   */\n    /**\n     * @api {POST} /auth/login/google Social Login\n     * @apiName google\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    this.router.get(\"/login/google\", GoogleRoutes.authenticate());\n    this.router.get(\n      \"/callback/google\",\n      GoogleRoutes.callback(),\n      this.redirectSocialUser\n    );\n\n    /**\n     * @api {POST} /auth/login/twitter Social Login\n     * @apiName twitter\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    /*this.router.get(\"/login/twitter\", TwitterRoute.authenticate(\"twitter\"));\n    this.router.get(\n      \"/callback/twitter\",\n      TwitterRoute.callback(),\n      this.redirectSocialUser\n    ); */\n\n    /**\n     * @api {POST} /auth/login/linkedin Social Login\n     * @apiName linkedin\n     * @apiGroup Auth\n     * @apiSuccess {String} code HTTP status code from API.\n     * @apiSuccess {String} message Message from API.\n     */\n    /*\n    this.router.get(\"/login/likedin\", LinkedinRoutes.authenticate());\n    this.router.get(\"/login/linkedin\", LinkedinRoutes.authenticate());\n    this.router.get(\n      \"/callback/linkedin\",\n      LinkedinRoutes.callback(),\n      this.redirectSocialUser\n    ); */\n  }\n}\n\n// Create the HeroRouter, and export its configured Express.Router\nconst authRoutes = new AuthRouter();\nauthRoutes.init();\n\nexport default authRoutes.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes/userRoutes.ts",
    "content": "import * as express from \"express\";\nconst router = express.Router();\nconst passport = require(\"passport\");\nimport UserController from \"../controller/UserController\";\nconst jwt = require(\"jsonwebtoken\");\n// seralize user Object\nimport  ResponseTemplate from '../global/templates/response';\nimport * as expressJoiValidator from \"express-joi-validator\";\nimport expressJoi from \"../lib/requestValidator\";\nconst boom = require(\"express-boom\");\nimport { Router } from \"express\";\nconst path = require('path')\nconst fs = require('fs');\nconst { uploadpath } = global['configuration']\nconst multer = require('multer');\nimport Helper from '../helper/bcrypt';\n\n\nlet profileStorage = multer.diskStorage({\n\tdestination: function (req, file, cb) {\n\t\tcb( null, path.join( uploadpath.uploaddir, uploadpath.profiledir ) );\n\t},\n\tfilename: function (req, file, cb) {\n\t\tlet extension = Helper.getFileExtension(file.originalname);\n\t\tcb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` );\n\t}\n})\nlet upload = multer({ storage: profileStorage });\n\nlet documentStorage = multer.diskStorage({\n\tdestination: function (req, file, cb) {\n\t\tcb( null, path.join( uploadpath.uploaddir, uploadpath.documentdir ) );\n\t},\n\tfilename: function (req, file, cb) {\n\t\tlet extension = Helper.getFileExtension(file.originalname);\n\t\tcb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` );\n\t}\n})\nlet uploadDocuments = multer({ storage: documentStorage });\n\n\nexport class AuthRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n    this.init();\n  }\n\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\npublic resetPassword(req, res){\n\t\tUserController.resetPassword( req.body.email, ( error, success) => {\n\t\t\tconsole.log(error)\n\t\t\tif ( error ) {\n\t\t\t\tres.status(403).json({success : false, message: error, description: 'error occoured while resetting password' });\n\t\t\t} else {\n\t\t\t\tres.json({\n\t\t\t\t\tstatusCode: 200,\n\t\t\t\t\tmessage: 'success',\n\t\t\t\t\tdescription: 'if this email is registered with us, you will receive a password reset email soon.',\n\t\t\t\t});\n\t\t\t}\n\t\t});\n};\n\npublic updateUser(req, res){\n  UserController.updateUser(req.params.email, req.body ,( error, success) => {\n    if ( error ) {\n      res.status(403).json({success : false, message: error, description: 'error occoured while updating user' });\n    } else {\n      res.json({\n        statusCode: 200,\n        message: 'success',\n        description: 'user updated successfully',\n      });\n    }\n  });\n}\npublic getUserByEmail(req, res){\n  UserController.getUserByEmail(req.params.email ,( error, user) => {\n    if ( error ) {\n      res.status(403).json({success : false, message: error, description: 'error occoured while updating user' });\n    } else {\n      res.json({\n        statusCode: 200,\n        message: 'success',\n        data: user\n      });\n    }\n  });\n}\n\npublic uploadProfilepicture(req, res){\n  UserController.updateUser( req.user.email, { picture: req.file.filename }, ( error, user ) => {\n\t\tif ( error ) {\n\t\t\tres.json( ResponseTemplate.updateErrorOccoured(error) );\n\t\t} else {\n\t\t\tres.json( ResponseTemplate.success(\n\t\t\t\t'your profile picture has been successfully uploaded',\n\t\t\t\t{ picture: Helper.avatarURL(user.picture) })\n\t\t\t);\n\t\t  Helper.deleteFile( 'profile', req.user.picture );\n\t\t}\n\t});\n}\n// upload users profile picture.\npublic uploadDocuments(req, res){\n  let documents:any = {};\n\treq.files.map( (file) => {\n\t\tdocuments.url = file.filename;\n\t\tdocuments.originalname = file.originalname;\n\t\tdocuments.timestamp = new Date();\n\t});\n\n\tUserController.updateUser( req.user.email, { document: documents }, ( error, user ) => {\n\t\tif ( error ) {\n\t\t\tres.json( ResponseTemplate.updateErrorOccoured(error) );\n\t\t} else {\n\t\t\tlet userDocuments = [];\n\t\t\tif ( user.documents ) {\n\t\t\t\tuser.documents.map( (doc) => {\n\t\t\t\t\tuserDocuments.push( Helper.userDocumentURL(doc.url) );\n\t\t\t\t});\n\t\t\t}\n\t\t\tres.json( ResponseTemplate.success(\n\t\t\t\t'host documents have been successfully uploaded',\n\t\t\t\t{ documents: userDocuments })\n\t\t\t);\n\t\t}\n\t});\n}\n\n  /**\n   * Take each handler, and attach to one of the Express.Router's\n   * endpoints.\n   */\n  init() {\n    this.router.get(\"/:email\", this.getUserByEmail);\n    this.router.get(\"/reset-password/:email\",expressJoiValidator(expressJoi.resetPassword),  this.resetPassword);\n    this.router.put(\"/update/:email\", this.updateUser);\n    this.router.post('/upload-profile-picture', upload.single('avatar'), this.uploadProfilepicture);\n    this.router.post('/upload-documents', uploadDocuments.array('documents'), this.uploadDocuments);\n  }\n}\n\n// Create the HeroRouter, and export its configured Express.Router\nconst authRoutes = new AuthRouter();\nauthRoutes.init();\n\nexport default authRoutes.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/routes.ts",
    "content": "/* eslint func-names: [\"error\", \"never\"] */\n/* eslint prefer-destructuring: 0 */\nimport * as express from 'express';\nconst expressRouter= express.Router();\nimport authRoutes from './routes/routes';\nimport userRoutes from './routes/userRoutes';\nimport defaultRoutes from './routes/defaultRoutes';\nimport validAuthTokenMiddleware from './middleware/authMiddleware';\nexpressRouter.use('/', defaultRoutes);\nexpressRouter.use('/uploads/', express.static('uploads'));\nexpressRouter.use('/auth', authRoutes);\nexpressRouter.use('/user',validAuthTokenMiddleware.validateToken, userRoutes);\n\n\n\nexport default expressRouter;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/seed/seedUsers.ts",
    "content": "import User from '../models/user';\n\nconst mongoose = require('mongoose');\n\nconst dbName = 'blabla';\nmongoose.connect(`mongodb://localhost/${dbName}`);\n/* eslint quote-props:0 */\n/* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */\n\nconst users = [\n  {\n    'username': 'tarun',\n    'email': 'tarun@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1222@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun22@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun5@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun6@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'asdfg@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tgfdsa@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },\n  {\n    'username': 'tarun1',\n    'email': 'tarunfgds8@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'asdfcv@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'dekoo@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'hellodemo@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  },{\n    'username': 'tarun1',\n    'email': 'gmail@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 16.5377266,\n      'lng': 79.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }\n];\n\nUser.collection.drop();\n\nUser.create(users, (err) => {\n  if (err) {\n    throw (err);\n  }\n  console.log(`Created ${users.length} User`);\n  mongoose.connection.close();\n});\n\n\n/* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal:\nnode ./bin/seeds.js. De esta manera se crea la base de datos */\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/seed/seedVehicle.ts",
    "content": "import User from '../models/user';\n\nconst mongoose = require('mongoose');\n\nconst dbName = 'blabla';\nmongoose.connect(`mongodb://localhost/${dbName}`);\n/* eslint quote-props:0 */\n/* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */\n\nconst users = [\n  {\n    'username': 'tarun',\n    'email': 'tarun@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1222@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun22@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun5@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun1@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun6@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun7@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }, {\n    'username': 'tarun1',\n    'email': 'tarun8@gmail.com',\n    'email_verified': true,\n    'phone_verified': false,\n    'gender': null,\n    'address': 'goa India',\n    'geo': {\n      'lat': 15.5377266,\n      'lng': 73.8316141\n    },\n    'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.',\n    'documents': [],\n    'status': '1',\n    'type': '2'\n  }\n];\n\nUser.collection.drop();\n\nUser.create(users, (err) => {\n  if (err) {\n    throw (err);\n  }\n  console.log(`Created ${users.length} User`);\n  mongoose.connection.close();\n});\n\n\n/* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal:\nnode ./bin/seeds.js. De esta manera se crea la base de datos */\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/transformer/userTransformer.ts",
    "content": "'use strict';\n\nimport _ from 'lodash';\n// import ReviewTransformer from './ReviewTransformer';\n\n\nlet UserTransformer = {\n  xx : (users) =>{\n    if ( Array.isArray(users) ) {\n\t\t\tlet output = [];\n\t\t\tusers.forEach(( user ) => {\n\t\t\t\toutput.push( UserTransformer._transformUsers(user) );\n\t\t\t});\n\t\t\treturn output;\n\t\t}\n\t\telse {\n\t\t\treturn UserTransformer._transformUsers(users);\n\t\t}\n  },\n  transform: (users) => {\n    if (Array.isArray(users)) {\n      let output = [];\n      users.forEach((user) => {\n        output.push(UserTransformer._transform(user));\n      });\n      return output;\n    }\n    else {\n      return UserTransformer._transform(users);\n    }\n  },\n  calculateUsers: (users: any | null) => {\n    if (Array.isArray(users)) {\n      return {\n        Users : users.length ? users.length : 100,\n        vehicles : (users['vehicle'] ) ? users['vehicle'].length : 1000,\n        cities :100\n      }\n    }\n  },\n\n  _transform: (user) => {\n    if (!user) { return {}; }\n    let user_status = (user.status === 1) ? 'active' : 'disabled';\n    return {\n      id: user._id,\n      username : user.username,\n      status: user_status,\n      name: user.name,\n      email: user.email,\n      password: (user.password) ? true : false,\n      phone: user.phone || '',\n      gender: user.gender || '',\n      birthday: user.birthday || '',\n      type: user.type || 1,\n      meta: user.meta || {},\n      social : user.social || [],\n      phone_verified: user.phone_verified ? true : false,\n      email_verified: user.email_verified ? true : false,\n      profile_picture: user.profile_picture ? null : null // will fix later\n    };\n  },\n  transformUsers: ( users ) => {\n\t\tif ( Array.isArray(users) ) {\n\t\t\tlet output = [];\n\t\t\tusers.forEach(( user ) => {\n\t\t\t\toutput.push( UserTransformer._transformUsers(user) );\n\t\t\t});\n\t\t\treturn output;\n\t\t}\n\t\telse {\n\t\t\treturn UserTransformer._transformUsers(users);\n\t\t}\n\t},\n\t_transformUsers: ( user ) => {\n\t\tif ( ! user ) { return {}; }\n    let user_status = ( user.status === '1' ) ? 'active' : 'disabled';\n    const obj:any = {};\n\n\t\treturn Object.assign({}, {\n      id: user._id,\n      username : user.username,\n      status: user_status,\n      name: user.name,\n      email_verified:user.email_verified,\n      phone_verified :user.phone_verified,\n      reviews : user.reviews,\n      vehciles : user.vehciles,\n      email: user.email,\n      date : user.createdAt,\n      type: user.type || 1,\n\t\t}, obj);\n  }\n}\n\nexport default UserTransformer;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/types/global.d.ts",
    "content": "declare namespace NodeJS {\n    export interface Global {\n      configuration: any\n    }\n  }"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/app/types/vendor.d.ts",
    "content": "\ndeclare namespace NodeJS {\n  export interface Global {\n    configuration: any\n  }\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/env.sh",
    "content": "# this environment vairables needs to be set in .env file in applciaiton root directory\n# copy this file as .env and add the appropriate values as per environment.\n# node & mysql\nexport NODE_ENV=\"dev\"\nexport PORT=\"3001\"\nexport MONGO_HOST=\"ms_commerce_mongo\"\nexport MONGO_PORT=\"27017\"\nexport MONGO_USERNAME=\"root\"\nexport MONGO_PASSWORD=\"root\"\nexport MONGO_DATABASE=\"ecommerce\"\n\nexport EXPRESS_SESSION_SECRET=\"######################\"\nexport F_CLIENTID=\"###################\"\nexport F_CLIENTSECRET=\"###########################\"\nexport F_CALLBACK=\"/auth/callback/facebook\"\nexport G_CLIENTID=\"@@@@@@@@@@@@@-###############.apps.%%%%%%%%%%%.com\"\nexport G_CLIENTSECRET=\"k##########@@@@@@@@@@@@Ub\"\nexport G_CALLBACK=\"/auth/callback/google\"\nexport L_CLIENTID=\"##################\"\nexport L_CLIENTSECRET=\"############\"\nexport L_CALLBACK=\"/auth/callback/linkedin\"\n\nexport T_CLIENTID=\"##################\"\nexport T_CLIENTSECRET=\"######################\"\nexport T_CALLBACK=\"/auth/callback/twitter\"\nexport FE_URL=\"localhost:3000\"\nexport API_KEY='XX0xxxxx-xX0X0XxXXxXxXXXxX0x'\nexport SMTP_HOST='smtp.mandrillapp.com'\nexport SMTP_PORT='587'\nexport SMTP_USER='#############.net'\nexport SMTP_PASSWORD='##############'\nexport SID='XX0xxxxx-xX0X0XxXXxXxXXXxX0x'\nexport TOKEN='XX0xxxxx-xX0X0XxXXxXxXXXxX0x'\nexport PHONE='+9716156786'\nexport FE='http://localhost:3000'\nexport API='http://localhost:3005'\nexport UPLOAD_DIR='uploads'\nexport PROFILE_PICTURE_DIR='profile'\nexport DOCUMENT_UPLOAD_DIR='documents'"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/express.ts",
    "content": "import router from './app/routes';\nimport * as boom from 'express-boom';\nimport * as expressSession from 'express-session';\nimport  * as cookieParser from 'cookie-parser';\nimport * as passport from 'passport';\nimport * as helmet from 'helmet';\nimport * as cors from 'cors';\nimport * as path from 'path';\nimport * as express from 'express';\nimport * as logger from 'morgan';\nimport * as bodyParser from 'body-parser';\nimport errorHandlers from './app/helper/errorHandler';\n// Creates and configures an ExpressJS web server.\nclass App {\n  // ref to Express instance\n  public express: express.Application;\n  //Run configuration methods on the Express instance.\n  constructor() {\n    this.express = express();\n    this.middleware();\n    this.routes();\n  }\n\n  // Configure Express middleware.\n  private middleware(): void {\n    this.express.use(passport.initialize());\n    // required for passport to initlize it\n    this.express.use(expressSession({ secret: 'bla bla' }));\n    this.express.use(passport.session());\n    // initlize session\n    this.express.use(logger('dev'));\n    this.express.disable('x-powered-by');\n    this.express.disable('etag');\n    this.express.use(helmet());\n    this.express.use(boom());\n    this.express.use(helmet.noCache({ noEtag: true })); // set Cache-Control header\n    this.express.use(helmet.noSniff()); // set X-Content-Type-Options header\n    this.express.use(helmet.frameguard()); // set X-Frame-Options header\n    this.express.use(helmet.xssFilter()); // set X-XSS-Protection header\n    // logger logs on console\n    this.express.use(bodyParser.urlencoded({ extended: false, limit: '5mb' })); // parse application/x-www-form-urlencoded\n    this.express.use(bodyParser.json()); // parse application/json\n    // enable CORS\n    this.express.use((req, res, next) => {\n      res.header('Access-Control-Allow-Origin', '*');\n      res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PATCH, OPTIONS');\n      res.header('Access-Control-Allow-Headers', 'Content-Type, api_key, Authorization, Referer');\n      next();\n    });\n    // register all custom Middleware\n    this.express.use(cors({ optionsSuccessStatus: 200 }));\n    this.express.use(cookieParser()); // cookies-parser\n    // manage session by cookies\n    this.express.set('views', path.join(__dirname, 'views')); // setting views\n    this.express.set('view engine', 'hbs');\n    // server side template rendering\n    this.express.use(express.static(path.join(__dirname, 'public')));\n    this.express.use(logger('dev'));\n    this.express.use(bodyParser.json());\n    this.express.use(bodyParser.urlencoded({ extended: false }));\n  }\n\n  // Configure API endpoints.\n  private routes(): void {\n    passport.serializeUser((user, done) => {\n      done(null, user);\n    });\n    passport.deserializeUser((user, done) => {\n      done(null, user);\n    });\n    /* This is just to get up and running, and to make sure what we've got is\n     * working so far. This function will change when we start to add more\n     * API endpoints */\n    this.express.use('/api/v1', router);\n    this.express.use(errorHandlers.internalServerError);\n    this.express.use(errorHandlers.PageNotFound);\n  }\n}\n\nexport default new App().express;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/package.json",
    "content": "{\n  \"name\": \"e-commerce-hub\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"cd dist &&  nodemon server.js\",\n    \"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n    \"startdev\": \". ./env.sh  && cd dist &&  nodemon  --inspect=0.0.0.0:9201 server.js && tsc --watch\",\n    \"clean\": \"rm -rf dist\",\n    \"watch\": \"tsc\",\n    \"copy\": \"cp -r uploads dist/ && cp -r app/global dist/app/\",\n    \"test\": \". ./env.sh  && NODE_ENV=test && mocha \",\n    \"debug\": \". ./env.sh && NODE_ENV=test && cd dist && nodemon  server.js\",\n    \"prestartdev\": \" npm run clean && tsc &&  npm run copy && npm run watch\",\n    \"poststartdev\": \"tsc --watch\",\n    \"watchserver\": \"tsc --watch\",\n    \"dev\": \". ./env.sh && ts-node server.ts\",\n    \"start-tsc\": \". ./env.sh && nodemon ./dist/server.js\",\n    \"buildAndstart\": \". ./env.sh && npm run build && npm run start\"\n  },\n  \"dependencies\": {\n    \"@types/express\": \"^4.11.1\",\n    \"assert\": \"^1.4.1\",\n    \"axios\": \"^0.18.0\",\n    \"bcrypt-nodejs\": \"0.0.3\",\n    \"bluebird\": \"^3.5.3\",\n    \"body-parser\": \"^1.18.3\",\n    \"cookie-parser\": \"^1.4.3\",\n    \"cors\": \"^2.8.5\",\n    \"dotenv\": \"^6.1.0\",\n    \"email-templates\": \"^2.7.1\",\n    \"express\": \"^4.16.4\",\n    \"express-boom\": \"^2.0.0\",\n    \"express-joi-validator\": \"^2.0.0\",\n    \"express-session\": \"^1.15.6\",\n    \"fast-csv\": \"^2.4.1\",\n    \"hbs\": \"^4.0.1\",\n    \"helmet\": \"^3.15.0\",\n    \"joi\": \"^14.1.1\",\n    \"jsonwebtoken\": \"^8.4.0\",\n    \"mocha\": \"^5.2.0\",\n    \"moment\": \"^2.22.2\",\n    \"mongoose\": \"^4.5.9\",\n    \"morgan\": \"^1.9.0\",\n    \"multer\": \"^1.2.0\",\n    \"nodemailer\": \"2.5.0\",\n    \"nodemon\": \"^1.18.6\",\n    \"passport\": \"0.3.2\",\n    \"passport-facebook\": \"2.1.1\",\n    \"passport-google-oauth\": \"1.0.0\",\n    \"passport-google-oauth20\": \"^1.0.0\",\n    \"passport-instagram\": \"1.0.0\",\n    \"passport-linkedin\": \"^1.0.0\",\n    \"passport-local\": \"1.0.0\",\n    \"passport-twitter\": \"1.0.4\",\n    \"pug\": \"2.0.0-beta6\",\n    \"serve-favicon\": \"^2.5.0\",\n    \"ts-lint\": \"^4.5.1\",\n    \"ts-node\": \"^7.0.1\",\n    \"twilio\": \"^2.11.1\",\n    \"typescript\": \"^3.1.6\",\n    \"uuid\": \"^3.3.2\",\n    \"winston\": \"^2.4.2\"\n  },\n  \"devDependencies\": {\n    \"@types/async\": \"^2.0.45\",\n    \"@types/bcrypt-nodejs\": \"^0.0.30\",\n    \"@types/bluebird\": \"^3.5.20\",\n    \"@types/body-parser\": \"^1.16.8\",\n    \"@types/express\": \"^4.11.1\",\n    \"@types/mongoose\": \"^4.7.34\",\n    \"@types/morgan\": \"^1.7.35\",\n    \"@types/node\": \"^9.6.39\",\n    \"@types/nodemailer\": \"^4.3.4\",\n    \"@types/passport\": \"^0.4.3\",\n    \"babel-eslint\": \"^8.0.1\",\n    \"eslint\": \"^4.19.1\",\n    \"eslint-config-airbnb-base\": \"^12.1.0\",\n    \"eslint-plugin-import\": \"^2.9.0\",\n    \"eslint-plugin-node\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/public/javascripts/script.js",
    "content": "document.addEventListener('DOMContentLoaded', () => {\n\n  console.log('IronGenerator JS imported successfully!');\n\n}, false);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/public/style.scss",
    "content": "body {\n  padding: 50px;\n  font: 14px \"Lucida Grande\", Helvetica, Arial, sans-serif;\n}\n\na {\n  color: #00B7FF;\n}\n\n.h1 {\n  font-size: 40px;\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/server.ts",
    "content": "import * as http from 'http';\nimport * as debug from 'debug';\n// After you declare \"app\"\nconst env = process.env.NODE_ENV || 'dev'\nconsole.log(` using ${process.env.NODE_ENV} to run application`);\nglobal.configuration = require(`./app/config/environments/${env}`);\nimport App from './express';\n\nconst port = (process.env.PORT);\nconst logger = require('winston');\nimport mongoose from './app/lib/mongoose';\nmongoose();\nconst server = http.createServer(App);\nserver.listen(process.env.PORT);\nserver.on('error', onError);\nserver.on('listening', onListening);\n\n\nfunction onError(error: NodeJS.ErrnoException): void {\n  if (error.syscall !== 'listen') throw error;\n  let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port;\n  switch(error.code) {\n    case 'EACCES':\n      console.error(`${bind} requires elevated privileges`);\n      process.exit(1);\n      break;\n    case 'EADDRINUSE':\n      console.error(`${bind} is already in use`);\n      process.exit(1);\n      break;\n    default:\n      throw error;\n  }\n}\n\nconst gracefulStopServer = function () {\n  // Wait 10 secs for existing connection to close and then exit.\n  setTimeout(() => {\n    logger.info('Shutting down server');\n    process.exit(0);\n  }, 1000);\n};\n\nprocess.on('uncaughtException', (err) => {\n  logger.error(err, 'Uncaught exception');\n  process.exit(1);\n});\n\nprocess.on('unhandledRejection', (reason, promise) => {\n  logger.error({\n    promise,\n    reason\n  }, 'unhandledRejection');\n  process.exit(1);\n});\n\nprocess.on('SIGINT', gracefulStopServer);\nprocess.on('SIGTERM', gracefulStopServer);\n\nfunction onListening(): void {\n  let addr = server.address();\n  let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`;\n  console.log(`Listening on ${bind}`);\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"moduleResolution\": \"node\",\n        \"pretty\": true,\n        \"sourceMap\": true,\n        \"target\": \"es6\",\n        \"outDir\": \"./dist\",\n        \"experimentalDecorators\": false,\n        \"emitDecoratorMetadata\": false,\n        \"skipDefaultLibCheck\": false,\n        \"baseUrl\": \"./lib\"\n    },\n    \"files\" : [\n        \"./app/types/vendor.d.ts\"\n    ],\n    \"include\": [\n        \"/**/*.ts\"\n    ],\n    \"exclude\": [\n        \"node_modules\"\n    ]\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/tslint.json",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/uploads/documents/.gitkeep",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Auth/uploads/profile/.gitkeep",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/.sequelizerc",
    "content": "const path = require('path');\n\nmodule.exports = {\n  'config': path.resolve('config', 'config.js')\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/Dockerfile",
    "content": "FROM node:carbon\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Bundle app source\nCOPY . .\n\n# npm install\nRUN  npm install\n# Run npm install --global grpc --unsafe-perm\n\nEXPOSE 3004 9204\nCMD [ \"npm\", \"run\", \"watchserver\" ]\nCMD [ \"npm\", \"run\", \"startdev\" ]\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/README.md",
    "content": "# Application for e-commerce Hub\n\n\nREST API to support application features\n\n  - Express as web framework with Typescript\n  - Passport js for social authentication \n  - Express CORS enabled\n  - boom for error codes & Joi for Validation\n  - Winston for logging and express minitor for monitoring\n  - Mongoose as ODM driver\n  - eslint validation extending airbnb styleguide \n  - git hooks & CI/CD in place\n  - Typescript based compilation tsc compiler\n  - TDD in progress with Mocha\n  - JWT based authentication\n  - multiple Mongoose collection with referencing\n  - payment gateway Integration\n  - Heroku deployment\n  - Mini e-commerce platform \n\n# Cart Application #\n\n\"It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills\n\n```\n# Application Execution\n```javascript\ngit clone  repo\nnpm install\nnpm run startdev\ntsc -- watch\n```\n# Application configuration\n```javascript\nenv.sh need to be added locally \nexport NODE_ENV=\"dev\"\nexport PORT=\"3005\"\nexport MONGOURL=\"mongodb://mongo/hello\"\nexport EXPRESS_SESSION_SECRET=\"************************\"\nexport F_CLIENTID=\"**************\"\nexport F_CLIENTSECRET=\"**********************\"\n```\n\n# Application NPM Script\n```javascript\n\"start\": \"cd dist &&  nodemon server.js\",\n\"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n\"clean\" : \"rm -rf dist\",\n\"copy\" : \"cp -r uploads dist/ && cp -r app/global dist/app/\"\n```\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/config/environments/dev.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.db = {\n  user: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  database: process.env.DATABASE,\n  host: process.env.HOST,\n  connectTimeout: 80000,\n};\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nconfiguration.logLevel ='info';\n\nmodule.exports = configuration;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/config/environments/qa.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.db = {\n  user: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  database: process.env.DATABASE,\n  host: process.env.HOST,\n  connectTimeout: 80000,\n};\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nconfiguration.logLevel ='info';\n\nmodule.exports = configuration;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/config/environments/test.ts",
    "content": "/* eslint quote-props: 0 */\nexport { }\nconst configuration: any = {};\nconfiguration.mongo = {\n  url:  process.env.MONGODB_URI || process.env.MONGOURL,\n};\nconfiguration.URL = {\n  frontEnd: process.env.FE_URL\n}\nconfiguration.db = {\n  user: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  database: process.env.DATABASE,\n  host: process.env.HOST,\n  connectTimeout: 80000,\n};\n\nconfiguration.facebook = {\n  client_id: process.env.F_CLIENTID,\n  client_secret: process.env.F_CLIENTSECRET,\n  callback_url: process.env.F_CALLBACK\n};\nconfiguration.google = {\n  client_id: process.env.G_CLIENTID,\n  client_secret: process.env.G_CLIENTSECRET,\n  callback_url: process.env.G_CALLBACK\n};\nconfiguration.linkedin = {\n  client_id: process.env.L_CLIENTID,\n  client_secret: process.env.L_CLIENTSECRET,\n  callback_url: process.env.L_CALLBACK\n};\nconfiguration.twitter = {\n  client_id: process.env.T_CLIENTID,\n  client_secret: process.env.T_CLIENTSECRET,\n  callback_url: process.env.T_CALLBACK\n};\nconfiguration.email = {\n  apiKey: process.env.API_KEY,\n  host: process.env.SMTP_HOST,\n  port: process.env.SMTP_PORT,\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASSWORD,\n  }\n}\nconfiguration.twilio = {\n  sid: process.env.SID,\n  token: process.env.TOKEN,\n  phone: process.env.PHONE,\n}\nconfiguration.url = {\n  FE: process.env.FE,\n  API: process.env.API,\n}\nconfiguration.uploadpath = {\n  uploaddir: process.env.UPLOAD_DIR,\n  profiledir: process.env.PROFILE_PICTURE_DIR\n}\nconfiguration.logLevel ='info';\n\nmodule.exports = configuration;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/events/processEvent.ts",
    "content": "const events = require('events');\n\nconst eventEmitter = new events.EventEmitter();\n\nexport default eventEmitter;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/helper/errorHandler.ts",
    "content": "import  logger from '../lib/logger';\nimport  ResponseTemplate from './responseTemplate';\n/* eslint class-methods-use-this:0 */\nconst env = process.env.NODE_ENV;\nconst onDevEnv = env === 'dev' || env === 'test' || env === 'local';\nclass errorHandler {\n  public internalServerError(err, req, res, next) {\n    logger.log('info',err);\n    if (err.isBoom) {\n      // Error From  joi express validator\n      const error = {\n        message: err.output.payload.error,\n        error: err.output.payload.message\n      };\n      res.status(400).json(ResponseTemplate.BadRequestFromJoi(error));\n    } else { // internalServerError\n      res.status(500).json({\n        success: false,\n        message: err.message,\n        error: (onDevEnv) ? err.stack : {}\n      });\n    }\n  }\n  public PageNotFound(req, res, err) {\n    res.status(404).json({ message: 'api not found' });\n  }\n}\n\nexport default new errorHandler();\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/helper/errors.ts",
    "content": "class APIError extends Error {\n  constructor(message, ErrorID, code = null) {\n    super();\n    Error.captureStackTrace(this, this.constructor);\n    this.name = 'api error';\n    this.message = message;\n    if (ErrorID) this['ErrorID'] = ErrorID;\n    if (code) this['code'] = code;\n  }\n}\nexport default APIError;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/helper/logger.ts",
    "content": "const log = require('loglevel');\n\nlog.setLevel(global.configuration.logLevel);\nconst logger = log;\nexport default  logger;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/helper/responseTemplate.ts",
    "content": "/* istanbul ignore file */\nconst data: any = {\n  general(data) {\n    return data;\n  },\n  successMessage(message) {\n    return {\n      success: true,\n      message\n    };\n  },\n  success(data, message) {\n    return {\n      success: true,\n      message,\n      data\n    };\n  },\n  error(message, err, code= null) {\n    return {\n      success: false,\n      message: message || 'some error occurred',\n      error: err || 'error occurred on server, please try again after some time.'\n    };\n  },\n  emptyContent() {\n    return this.general({\n      message: 'empty content found',\n      description: 'you must provide valid data and it must not be empty.',\n      helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json']\n    });\n  },\n  invalidContentType() {\n    return this.general({\n      message: 'invalid content type',\n      description: 'you must specify content type and it must be application/json',\n      helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type']\n    });\n  },\n  BadRequestFromJoi(err) {\n    return this.error(\n      err.message,\n      err.error\n    );\n  },\n  userAlreadyExist(err) {\n    return this.general({\n      success: false,\n      message: 'user already registered in System',\n      description: 'user already registered in System'\n    });\n  },\n  userdoesNotExist(err) {\n    return this.general({\n      success: false,\n      message: err.message || 'user not registered in system',\n      description: 'user account does not exist in system'\n    });\n  },\n  commonAuthUserDataError() {\n    return this.error(\n       'Authentication error',\n       'token verification failed, Please try again'\n    );\n  },\n  tokenRequiredAuthError() {\n    return this.error(\n      'Authentication error, Token is required in Header',\n      'token verification failed, Please try again'\n    );\n  },\n};\nexport default data;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/lib/logger.ts",
    "content": "const log = require('loglevel');\n\nlog.setLevel(global.configuration.logLevel);\nconst logger = log;\nexport default  logger;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/lib/mysql.ts",
    "content": "import APIError from  '../helper/errors';\nimport logger from './logger';\n\nconst mysql = require('mysql2');\nimport eventEmitter from '../events/processEvent';\n/* eslint func-names: [\"error\", \"never\"] */\nconst config = global['configuration'].db;\nconsole.log(config);\nlet connection:any = null;\n\ntry {\n  connection = mysql.createConnection(config);\n} catch (err) {\n  logger.error('Cannot establish a connection with the database');\n  /** To Prevent sensitive info leak, not raising  actual error */\n  throw new APIError('Mysql connection failed (config)', 1);\n}\nconnection.connect((err) => {\n  // in case of error\n  if (err) throw new APIError('Mysql connection failed (connect)', 1);\n  else {\n    logger.info(`MysqlClient connected to port ${config.port || 3306} and ${config.host} host`);\n    eventEmitter.emit('dbReady', connection);\n  }\n});\nconnection.on('error', (err) => {\n  logger.error('Cannot establish a connection with the database');\n  /** To Prevent sensitive info leak, not raising  actual error */\n  throw new APIError('Mysql connection failed (event)', 1);\n});\n\nexport default connection;\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/lib/requestValidator.ts",
    "content": "const Joi = require('joi');\n\nconst validation = {\n  loginUser : {\n    body : {\n    email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n    password: Joi.string().min(8).max(50).required()\n    }\n  },\n  createUser: {\n    body: {\n      username: Joi.string().min(4).max(50).required(),\n      password: Joi.string().min(8).max(50).required(),\n      email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n      verify_password: Joi.string().min(6).max(50).required()\n    },\n  },\n  resetPassword: {\n    body: {\n      email: Joi.string().regex(/^[\\w.]+@[\\w]+?(\\.[a-zA-Z]{2,3}){1,3}$/).required(),\n    }\n  }\n};\nexport default validation\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/middleware/requestValidator.ts",
    "content": "\nmodule.exports = {\n  validatePayload(req, res, next) {\n    // validatr token here is its valid here\n    const token = req.body;\n    if ((req.method === 'POST' || req.method === 'PUT') && req.body !== null) {\n      next();\n    }\n    res.status(403).json({ message: 'payload is required for HTTP Post & Put ' });\n  }\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/models/data/cart.ts",
    "content": "const Product= {\n  products: [\n    {\n      availableSizes: [\n        \"S\",\n        \"XS\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"4 MSL\",\n      id: 12,\n      installments: 9,\n      isFreeShipping: true,\n      price: 10.9,\n      sku: 12064273040195392,\n      style: \"Black with custom print\",\n      title: \"Cat Tee Black T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"M\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"\",\n      id: 13,\n      installments: 5,\n      isFreeShipping: true,\n      price: 29.45,\n      sku: 51498472915966370,\n      style: \"Front print and paisley print\",\n      title: \"Dark Thug Blue-Navy T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\",\n        \"XL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"GPX Poly 1\",\n      id: 14,\n      installments: 3,\n      isFreeShipping: true,\n      price: 9,\n      sku: 10686354557628304,\n      style: \"Front tie dye print\",\n      title: \"Sphynx Tie Dye Wine T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\",\n        \"XL\",\n        \"XXL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"Treino 2014\",\n      id: 15,\n      installments: 5,\n      isFreeShipping: true,\n      price: 14,\n      sku: 11033926921508488,\n      style: \"Black T-Shirt with front print\",\n      title: \"Skuul\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"\",\n      id: 11,\n      installments: 3,\n      isFreeShipping: true,\n      price: 13.25,\n      sku: 39876704341265610,\n      style: \"Wine\",\n      title: \"Wine Skul T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\",\n        \"XL\",\n        \"XXL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"14/15 s/nº\",\n      id: 0,\n      installments: 9,\n      isFreeShipping: true,\n      price: 10.9,\n      sku: 8552515751438644,\n      style: \"Branco com listras pretas\",\n      title: \"Cat Tee Black T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\",\n        \"XL\",\n        \"XXL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"14/15 s/nº\",\n      id: 1,\n      installments: 9,\n      isFreeShipping: true,\n      price: 10.9,\n      sku: 18644119330491310,\n      style: \"Preta com listras brancas\",\n      title: \"Sphynx Tie Dye Grey T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"14/15 s/nº\",\n      id: 2,\n      installments: 7,\n      isFreeShipping: true,\n      price: 14.9,\n      sku: 11854078013954528,\n      style: \"Branco com listras pretas\",\n      title: \"Danger Knife Grey\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"2014 s/nº\",\n      id: 3,\n      installments: 7,\n      isFreeShipping: true,\n      price: 14.9,\n      sku: 876661122392077,\n      style: \"Preto com listras brancas\",\n      title: \"White DGK Script Tee\"\n    },\n    {\n      availableSizes: [\n        \"XL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"14/15 s/nº - Jogador\",\n      id: 4,\n      installments: 12,\n      isFreeShipping: false,\n      price: 25.9,\n      sku: 9197907543445676,\n      style: \"Branco com listras pretas\",\n      title: \"Born On The Streets\"\n    },\n    {\n      availableSizes: [\n        \"X\",\n        \"L\",\n        \"XL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"14/15 + Camiseta 1º Mundial\",\n      id: 5,\n      installments: 9,\n      isFreeShipping: false,\n      price: 10.9,\n      sku: 10547961582846888,\n      style: \"Preto\",\n      title: \"Tso 3D Short Sleeve T-Shirt A\"\n    },\n    {\n      availableSizes: [\n        \"XL\",\n        \"XXL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"Goleiro 13/14\",\n      id: 6,\n      installments: 0,\n      isFreeShipping: true,\n      price: 49.9,\n      sku: 6090484789343891,\n      style: \"Branco\",\n      title: \"Man Tie Dye Cinza Grey T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"S\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"1977 Infantil\",\n      id: 7,\n      installments: 4,\n      isFreeShipping: true,\n      price: 22.5,\n      sku: 18532669286405344,\n      style: \"Preto com listras brancas\",\n      title: \"Crazy Monkey Black T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"XL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"\",\n      id: 8,\n      installments: 4,\n      isFreeShipping: false,\n      price: 18.7,\n      sku: 5619496040738316,\n      style: \"Azul escuro\",\n      title: \"Tso 3D Black T-Shirt\"\n    },\n    {\n      availableSizes: [\n        \"L\",\n        \"XL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"\",\n      id: 9,\n      installments: 5,\n      isFreeShipping: true,\n      price: 134.9,\n      sku: 11600983276356164,\n      style: \"\",\n      title: \"Crazy Monkey Grey\"\n    },\n    {\n      availableSizes: [\n        \"L\",\n        \"XL\"\n      ],\n      currencyFormat: \"$\",\n      currencyId: \"USD\",\n      description: \"\",\n      id: 10,\n      installments: 9,\n      isFreeShipping: true,\n      price: 49,\n      sku: 27250082398145996,\n      style: \"\",\n      title: \"On The Streets Black T-Shirt\"\n    }\n  ]\n};\n\n\nexport default Product; "
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/routes/defaultRoutes.ts",
    "content": "import * as express from \"express\";\nconst router = express.Router();\n\nimport { Router } from \"express\";\nimport product from '../models/data/cart';\n\n\nexport class DefaultRouter {\n  router: Router;\n\n  /**\n   * Initialize the HeroRouter\n   */\n  constructor() {\n    this.router = Router();\n  }\n  /**\n * @api {POST} /auth/reset-password update password sent in Mail\n * @apiName resetPassword\n * @apiGroup Auth\n * @apiSuccess {String} code HTTP status code from API.\n * @apiSuccess {String} message Message from API.\n */\n  public sayHello(req, res) {\n    res.status(200).json({ success: true, message: 'i am up and running with mysql + node .. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️' });\n  };\n  public getProducts(req, res) {\n    res.status(200).json(product);\n  };\n\n  init() {\n    this.router.get(\"/\", this.sayHello);\n    this.router.get(\"/products\", this.getProducts);\n\n  }\n}\n\n\n// Create the HeroRouter, and export its configured Express.Router\nconst defaultRouter = new DefaultRouter();\ndefaultRouter.init();\n\nexport default defaultRouter.router;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/routes.ts",
    "content": "/* eslint func-names: [\"error\", \"never\"] */\n/* eslint prefer-destructuring: 0 */\nimport * as express from 'express';\nconst expressRouter= express.Router();\nimport defaultRoutes from './routes/defaultRoutes';\nexpressRouter.use('/', defaultRoutes);\n\n\n\nexport default expressRouter;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/types/global.d.ts",
    "content": "declare namespace NodeJS {\n    export interface Global {\n      configuration: any\n    }\n  }"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/app/types/vendor.d.ts",
    "content": "\ndeclare namespace NodeJS {\n  export interface Global {\n    configuration: any\n  }\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/config/config.js",
    "content": "const fs = require('fs');\nmodule.exports = {\n  local: {\n    username: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    dialect: 'mysql'\n  },\n  dev: {\n    username: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    dialect: 'mysql'\n  },\n  test: {\n    username: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    dialect: 'mysql'\n  },\n  qa: {\n    username: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    dialect: 'mysql'\n  },\n  uat: {\n    username: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    dialect: 'mysql'\n  },\n  prod: {\n    username: process.env.USERNAME,\n    password: process.env.PASSWORD,\n    database: process.env.DATABASE,\n    host: process.env.HOST,\n    dialect: 'mysql'\n  }\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/env.sh",
    "content": "# this environment vairables needs to be set in .env file in applciaiton root directory\n# copy this file as .env and add the appropriate values as per environment.\n# node & mysql\nexport NODE_ENV=\"dev\"\nexport PORT=\"3004\"\nexport USERNAME=\"root\"\nexport PASSWORD=\"root\"\nexport DATABASE=\"cartDB\"\nexport HOST=\"mysql\""
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/express.ts",
    "content": "import router from './app/routes';\nimport * as boom from 'express-boom';\nimport * as expressSession from 'express-session';\nimport  * as cookieParser from 'cookie-parser';\nimport * as passport from 'passport';\nimport * as helmet from 'helmet';\nimport * as cors from 'cors';\nimport * as path from 'path';\nimport * as express from 'express';\nimport * as logger from 'morgan';\nimport * as bodyParser from 'body-parser';\nimport errorHandlers from './app/helper/errorHandler';\n\n// Creates and configures an ExpressJS web server.\nclass App {\n  // ref to Express instance\n  public express: express.Application;\n  //Run configuration methods on the Express instance.\n  constructor() {\n    this.express = express();\n    this.middleware();\n    this.routes();\n  }\n\n  // Configure Express middleware.\n  private middleware(): void {\n    this.express.use(passport.initialize());\n    // required for passport to initlize it\n    this.express.use(expressSession({ secret: 'bla bla' }));\n    this.express.use(passport.session());\n    // initlize session\n    this.express.use(logger('dev'));\n    this.express.disable('x-powered-by');\n    this.express.disable('etag');\n    this.express.use(helmet());\n    this.express.use(boom());\n    this.express.use(helmet.noCache({ noEtag: true })); // set Cache-Control header\n    this.express.use(helmet.noSniff()); // set X-Content-Type-Options header\n    this.express.use(helmet.frameguard()); // set X-Frame-Options header\n    this.express.use(helmet.xssFilter()); // set X-XSS-Protection header\n    // logger logs on console\n    this.express.use(bodyParser.urlencoded({ extended: false, limit: '5mb' })); // parse application/x-www-form-urlencoded\n    this.express.use(bodyParser.json()); // parse application/json\n    // enable CORS\n    this.express.use((req, res, next) => {\n      res.header('Access-Control-Allow-Origin', '*');\n      res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PATCH, OPTIONS');\n      res.header('Access-Control-Allow-Headers', 'Content-Type, api_key, Authorization, Referer');\n      next();\n    });\n    // register all custom Middleware\n    this.express.use(cors({ optionsSuccessStatus: 200 }));\n    this.express.use(cookieParser()); // cookies-parser\n    // manage session by cookies\n    this.express.set('views', path.join(__dirname, 'views')); // setting views\n    this.express.set('view engine', 'hbs');\n    // server side template rendering\n    this.express.use(express.static(path.join(__dirname, 'public')));\n    this.express.use(logger('dev'));\n    this.express.use(bodyParser.json());\n    this.express.use(bodyParser.urlencoded({ extended: false }));\n  }\n\n  // Configure API endpoints.\n  private routes(): void {\n    passport.serializeUser((user, done) => {\n      done(null, user);\n    });\n    passport.deserializeUser((user, done) => {\n      done(null, user);\n    });\n    /* This is just to get up and running, and to make sure what we've got is\n     * working so far. This function will change when we start to add more\n     * API endpoints */\n    this.express.use('/api/v1', router);\n    this.express.use(errorHandlers.internalServerError);\n    this.express.use(errorHandlers.PageNotFound);\n  }\n\n}\n\nexport default new App().express;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/mysql/schema.sql",
    "content": "CREATE DATABASE  IF NOT EXISTS `shopping_cart_db` /*!40100 DEFAULT CHARACTER SET utf8 */;\nUSE `shopping_cart_db`;\n\n\nDROP TABLE IF EXISTS `carts`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `carts` (\n  `idcarts` bigint(20) NOT NULL,\n  `idcustomer` bigint(20) NOT NULL,\n  `subtotal` decimal(10,2) NOT NULL,\n  PRIMARY KEY (`idcarts`),\n  KEY `carts_customers_fk_idx` (`idcustomer`),\n  CONSTRAINT `carts_customers_fk` FOREIGN KEY (`idcustomer`) REFERENCES `customers` (`idcustomer`) ON UPDATE CASCADE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `categories`\n--\n\nDROP TABLE IF EXISTS `categories`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `categories` (\n  `idcategory` int(11) NOT NULL AUTO_INCREMENT,\n  `description` varchar(20) NOT NULL,\n  PRIMARY KEY (`idcategory`)\n) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 PACK_KEYS=0;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `customers`\n--\n\nDROP TABLE IF EXISTS `customers`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `customers` (\n  `idcustomer` bigint(20) NOT NULL AUTO_INCREMENT,\n  `first_name` varchar(50) NOT NULL,\n  `last_name` varchar(50) NOT NULL,\n  `username` varchar(50) NOT NULL,\n  `password` varchar(256) NOT NULL,\n  PRIMARY KEY (`idcustomer`)\n) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `lines_item`\n--\n\nDROP TABLE IF EXISTS `lines_item`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `lines_item` (\n  `idlines_item` bigint(20) NOT NULL AUTO_INCREMENT,\n  `idorder` bigint(20) DEFAULT NULL,\n  `idproduct` bigint(20) NOT NULL,\n  `quantity` int(11) NOT NULL,\n  `price` decimal(10,2) NOT NULL,\n  `idcart` bigint(20) NOT NULL,\n  PRIMARY KEY (`idlines_item`),\n  KEY `lines_item_orders_fk_idx` (`idorder`),\n  KEY `lines_item_products_fk_idx` (`idproduct`),\n  KEY `lines_item_carts_fk_idx` (`idcart`),\n  CONSTRAINT `lines_item_orders_fk` FOREIGN KEY (`idorder`) REFERENCES `orders` (`idcustomer`) ON UPDATE CASCADE,\n  CONSTRAINT `lines_item_carts_fk` FOREIGN KEY (`idcart`) REFERENCES `carts` (`idcarts`) ON UPDATE CASCADE,\n  CONSTRAINT `lines_item_products_fk` FOREIGN KEY (`idproduct`) REFERENCES `products` (`idproduct`) ON DELETE NO ACTION ON UPDATE NO ACTION\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `orders`\n--\n\nDROP TABLE IF EXISTS `orders`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `orders` (\n  `idorder` bigint(20) NOT NULL AUTO_INCREMENT,\n  `ordered` datetime NOT NULL,\n  `status` varchar(20) NOT NULL,\n  `idcustomer` bigint(20) NOT NULL,\n  `total` decimal(10,2) NOT NULL,\n  PRIMARY KEY (`idorder`),\n  KEY `orders_customers_fk_idx` (`idcustomer`),\n  CONSTRAINT `orders_customers_fk` FOREIGN KEY (`idcustomer`) REFERENCES `customers` (`idcustomer`) ON UPDATE CASCADE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `products`\n--\n\nDROP TABLE IF EXISTS `products`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `products` (\n  `idproduct` bigint(20) NOT NULL AUTO_INCREMENT,\n  `description` varchar(100) NOT NULL,\n  `price` decimal(10,2) NOT NULL,\n  `idcategory` int(11) DEFAULT NULL,\n  PRIMARY KEY (`idproduct`),\n  KEY `products_categories_fk` (`idcategory`),\n  CONSTRAINT `products_categories_fk` FOREIGN KEY (`idcategory`) REFERENCES `categories` (`idcategory`) ON UPDATE CASCADE\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/package.json",
    "content": "{\n  \"name\": \"e-commerce-hub\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start:local\": \" . ./env.sh && NODE_ENV=local nodemon app/server.js \",\n    \"create:local\": \". ./env.sh && NODE_ENV=local ./node_modules/.bin/sequelize db:create\",\n    \"migrate:local\": \". ./env.sh && NODE_ENV=local ./node_modules/.bin/sequelize db:migrate\",\n    \"seed:local\": \" . ./env.sh && NODE_ENV=local ./node_modules/.bin/sequelize db:migrate --migrations-path seeders\",\n    \"start\": \"cd dist &&  nodemon server.js\",\n    \"prestart\": \"tsc && cp -r uploads dist/ && cp -r app/global dist/app/\",\n    \"startdev\": \". ./env.sh  && cd dist &&  nodemon server.js\",\n    \"clean\": \"rm -rf dist\",\n    \"watch\": \"tsc\",\n    \"copy\": \"cp -r uploads dist/ && cp -r app/global dist/app/\",\n    \"test\": \". ./env.sh  && NODE_ENV=test && mocha \",\n    \"debug\": \". ./env.sh && NODE_ENV=test && cd dist && nodemon --inspect=0.0.0.0:9230 server.js\",\n    \"prestartdev\": \" npm run clean && tsc &&  npm run copy && npm run watch\",\n    \"poststartdev\": \"tsc --watch\",\n    \"watchserver\": \"tsc --watch\",\n    \"dev\": \". ./env.sh && ts-node server.ts\",\n    \"start-tsc\": \". ./env.sh && nodemon ./dist/server.js\",\n    \"buildAndstart\": \". ./env.sh && npm run build && npm run start\"\n  },\n  \"dependencies\": {\n    \"@types/express\": \"^4.11.1\",\n    \"assert\": \"^1.4.1\",\n    \"axios\": \"^0.18.0\",\n    \"bcrypt-nodejs\": \"0.0.3\",\n    \"bluebird\": \"^3.5.3\",\n    \"body-parser\": \"^1.18.3\",\n    \"cookie-parser\": \"^1.4.3\",\n    \"cors\": \"^2.8.5\",\n    \"dotenv\": \"^6.1.0\",\n    \"email-templates\": \"^2.7.1\",\n    \"express\": \"^4.16.4\",\n    \"express-boom\": \"^2.0.0\",\n    \"express-joi-validator\": \"^2.0.0\",\n    \"express-session\": \"^1.15.6\",\n    \"fast-csv\": \"^2.4.1\",\n    \"hbs\": \"^4.0.1\",\n    \"helmet\": \"^3.15.0\",\n    \"joi\": \"^14.1.1\",\n    \"jsonwebtoken\": \"^8.4.0\",\n    \"loglevel\": \"^1.6.1\",\n    \"mocha\": \"^5.2.0\",\n    \"moment\": \"^2.22.2\",\n    \"mongoose\": \"^4.5.9\",\n    \"morgan\": \"^1.9.0\",\n    \"multer\": \"^1.2.0\",\n    \"mysql2\": \"^1.6.5\",\n    \"nodemailer\": \"2.5.0\",\n    \"nodemon\": \"^1.18.6\",\n    \"passport\": \"0.3.2\",\n    \"passport-facebook\": \"2.1.1\",\n    \"passport-google-oauth\": \"1.0.0\",\n    \"passport-google-oauth20\": \"^1.0.0\",\n    \"passport-instagram\": \"1.0.0\",\n    \"passport-linkedin\": \"^1.0.0\",\n    \"passport-local\": \"1.0.0\",\n    \"passport-twitter\": \"1.0.4\",\n    \"pug\": \"2.0.0-beta6\",\n    \"sequelize\": \"^4.37.4\",\n    \"sequelize-cli\": \"^4.0.0\",\n    \"serve-favicon\": \"^2.5.0\",\n    \"ts-lint\": \"^4.5.1\",\n    \"ts-node\": \"^7.0.1\",\n    \"twilio\": \"^2.11.1\",\n    \"typescript\": \"^3.1.6\",\n    \"uuid\": \"^3.3.2\"\n  },\n  \"devDependencies\": {\n    \"@types/async\": \"^2.0.45\",\n    \"@types/bcrypt-nodejs\": \"^0.0.30\",\n    \"@types/bluebird\": \"^3.5.20\",\n    \"@types/body-parser\": \"^1.16.8\",\n    \"@types/express\": \"^4.11.1\",\n    \"@types/mongoose\": \"^4.7.34\",\n    \"@types/morgan\": \"^1.7.35\",\n    \"@types/node\": \"^9.6.39\",\n    \"@types/nodemailer\": \"^4.3.4\",\n    \"@types/passport\": \"^0.4.3\",\n    \"babel-eslint\": \"^8.0.1\",\n    \"eslint\": \"^4.19.1\",\n    \"eslint-config-airbnb-base\": \"^12.1.0\",\n    \"eslint-plugin-import\": \"^2.9.0\",\n    \"eslint-plugin-node\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/public/javascripts/script.js",
    "content": "document.addEventListener('DOMContentLoaded', () => {\n\n  console.log('IronGenerator JS imported successfully!');\n\n}, false);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/public/style.scss",
    "content": "body {\n  padding: 50px;\n  font: 14px \"Lucida Grande\", Helvetica, Arial, sans-serif;\n}\n\na {\n  color: #00B7FF;\n}\n\n.h1 {\n  font-size: 40px;\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/server.ts",
    "content": "import * as http from 'http';\nimport * as debug from 'debug';\n// After you declare \"app\"\nconst env = process.env.NODE_ENV || 'dev'\nconsole.log(` using ${process.env.NODE_ENV} to run application`);\nglobal.configuration = require(`./app/config/environments/${env}`);\nimport App from './express';\nimport eventEmitter from './app/events/processEvent'\nconst port = (process.env.PORT);\nimport logger from './app/lib/logger';\nimport mysql from './app/lib/mysql';\nglobal['connection'] = mysql\n\nconst appServer = http.createServer(App);\n\nappServer.on('error', onError);\nappServer.on('listening', onListening);\n\n\nif (!module.parent) {\n  eventEmitter.on('dbReady', (connection) => {\n    const port = process.env.PORT;\n     appServer.listen(process.env.PORT,\n      () => {\n        logger.info(`API running in environment ${process.env.NODE_ENV}`);\n        logger.info(`API running at http://localhost:${port}`);\n      },\n    );\n    appServer.setTimeout(200000);\n    if (process['parent']) process.send('ready');\n  });\n}\n\n\nfunction onError(error: NodeJS.ErrnoException): void {\n  if (error.syscall !== 'listen') throw error;\n  let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port;\n  switch(error.code) {\n    case 'EACCES':\n      console.error(`${bind} requires elevated privileges`);\n      process.exit(1);\n      break;\n    case 'EADDRINUSE':\n      console.error(`${bind} is already in use`);\n      process.exit(1);\n      break;\n    default:\n      throw error;\n  }\n}\n\nconst gracefulStopServer = function () {\n  // Wait 10 secs for existing connection to close and then exit.\n  setTimeout(() => {\n    logger.info('Shutting down server');\n    process.exit(0);\n  }, 1000);\n};\n\nprocess.on('uncaughtException', (err) => {\n  logger.error(err, 'Uncaught exception');\n  process.exit(1);\n});\n\nprocess.on('unhandledRejection', (reason, promise) => {\n  logger.error({\n    promise,\n    reason\n  }, 'unhandledRejection');\n  process.exit(1);\n});\n\nprocess.on('SIGINT', gracefulStopServer);\nprocess.on('SIGTERM', gracefulStopServer);\n\nfunction onListening(): void {\n  let addr = appServer.address();\n  let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`;\n  debug(`Listening on ${bind}`);\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"moduleResolution\": \"node\",\n        \"pretty\": true,\n        \"sourceMap\": true,\n        \"target\": \"es6\",\n        \"outDir\": \"./dist\",\n        \"experimentalDecorators\": false,\n        \"emitDecoratorMetadata\": false,\n        \"skipDefaultLibCheck\": false,\n        \"baseUrl\": \"./lib\"\n    },\n    \"files\" : [\n        \"./app/types/vendor.d.ts\"\n    ],\n    \"include\": [\n        \"/**/*.ts\"\n    ],\n    \"exclude\": [\n        \"node_modules\"\n    ]\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/tslint.json",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/uploads/documents/.gitkeep",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Cart/uploads/profile/.gitkeep",
    "content": ""
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/Dockerfile",
    "content": "FROM node:carbon\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Bundle app source\nCOPY . .\n\n# npm install\nRUN  npm install\n# Run npm install --global grpc --unsafe-perm\n\nEXPOSE 3003\n\nCMD [ \"npm\", \"run\", \"start\" ]"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/README.md",
    "content": "##  Simple ecommerce cart application\n\n## Basic Overview -\n\nThis simple shopping cart prototype shows how React components and Redux can be used to build a\nfriendly user experience with instant visual updates and scaleable code in ecommerce applications.\n\n#### Features\n\n- Add and remove products from the floating cart\n- Sort products by highest to lowest and lowest to highest price\n- Filter products by available sizes\n- Products persist in floating cart even after page reloads\n- Responsive design for desktop, tablets and mobile\n- Product stoppers for free shipping\n- Unit tests, integration tests and e2e testing\n\n#### Using\n\n- React\n  - Redux - state management\n- Nodejs\n  - Express CORS Middleware (Node and React run in different port)\n  - Nodemon - for a better development experience\n  - Concurrently - To run multiple tasks at once\n- Axios - for promise HTTP requests\n- CSS\n  - BEM methodology\n  - SASS\n- Moxios - to stub http request\n- Enzyme - to mount, shallow, render and query the DOM tree of React components\n- Webdriverio - to do automated tests in a real browser environment\n- Native local storage - to persist products in cart even after page reload\n\n#### Requirements\n\n- Node.js\n- NPM\n\n```javascript\n\n/* First, Install the needed packages */\nnpm install\n\n/* Then start both Node and React */\nnpm start\n\n/* To run the tests */\nnpm run test\n\n/* Running e2e tests */\nnpm run wdio\n\n\n```\n\n## About tests\n\n- Unit tests\n  - All components have at least a basic smoke test\n- Integration tests\n  - Fetch product and add to cart properly\n- e2e\n  - Webdriverio - Add and remove product from cart\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/env.sh",
    "content": "# this environment vairables needs to be set in .env file in applciaiton root directory\n# copy this file as .env and add the appropriate values as per environment.\n# node & mysql\nexport NODE_ENV=\"local\"\nexport PORT=\"3003\""
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/firebase.json",
    "content": "{\n  \"hosting\": {\n    \"public\": \"build\",\n    \"ignore\": [\n      \"firebase.json\",\n      \"**/.*\",\n      \"**/node_modules/**\"\n    ]\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/package.json",
    "content": "{\n  \"name\": \"app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"antd\": \"^3.13.2\",\n    \"axios\": \"^0.18.0\",\n    \"concurrently\": \"^4.0.1\",\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.16.4\",\n    \"immutable\": \"^4.0.0-rc.12\",\n    \"moxios\": \"^0.4.0\",\n    \"react\": \"^16.6.1\",\n    \"react-dom\": \"^16.6.1\",\n    \"react-redux\": \"^5.1.1\",\n    \"react-router\": \"^3.2.0\",\n    \"react-router-dom\": \"^4.3.1\",\n    \"react-scripts\": \"^2.1.3\",\n    \"redux\": \"^4.0.1\",\n    \"redux-thunk\": \"^2.3.0\"\n  },\n  \"scripts\": {\n    \"start\": \". ./env.sh  &&  react-scripts start\",\n    \"wdio\": \"wdio\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"test:coverage\": \"npm run test -- --coverage\",\n    \"format\": \"prettier --write \\\"**/*.+(js|json|css)\\\"\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"react-app\"\n  },\n  \"jest\": {\n    \"collectCoverageFrom\": [\n      \"src/**/*.{js,jsx}\",\n      \"!/node_modules/\",\n      \"!src/index.js\",\n      \"!src/Root.js\"\n    ]\n  },\n  \"browserslist\": [\n    \">0.2%\",\n    \"not dead\",\n    \"not ie <= 11\",\n    \"not op_mini all\"\n  ],\n  \"devDependencies\": {\n    \"chai\": \"^4.2.0\",\n    \"enzyme\": \"^3.7.0\",\n    \"enzyme-adapter-react-16\": \"^1.7.0\",\n    \"enzyme-to-json\": \"^3.3.4\",\n    \"fetch-mock\": \"^7.2.5\",\n    \"firebase-tools\": \"^6.2.2\",\n    \"node-sass\": \"^4.10.0\",\n    \"nodemon\": \"^1.18.6\",\n    \"prop-types\": \"^15.6.2\",\n    \"react-test-renderer\": \"^16.6.3\",\n    \"redux-mock-store\": \"^1.5.3\",\n    \"sinon\": \"^7.1.1\",\n    \"wdio-mocha-framework\": \"^0.6.4\",\n    \"wdio-selenium-standalone-service\": \"0.0.12\",\n    \"wdio-spec-reporter\": \"^0.1.5\",\n    \"webdriverio\": \"^4.14.1\"\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <!-- Global site tag (gtag.js) - Google Analytics -->\n    <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-85006284-3\"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n\n      gtag('config', 'UA-85006284-3');\n    </script>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n    <meta name=\"theme-color\" content=\"#000000\">\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n    <link href=\"favicon.ico\" rel=\"shortcut icon\" type=\"image/x-icon\"/>\n    <link rel=\"sitemap\" type=\"application/xml\" title=\"Sitemap\" href=\"sitemap.xml\" />\n    <link href=\"https://react-shopping-cart-67954.firebaseapp.com/\" rel=\"shortcut icon\" type=\"image/x-icon\"/>\n    <meta name=\"google-site-verification\" content=\"b3ZTH-20AJ_8zTxSKYQ3TpQVS8dBirMtVapuIXT70dg\" />\n    <meta name=\"url\" content=\"https://react-shopping-cart-67954.firebaseapp.com/\"/>\n    <meta name=\"keywords\" content=\"react, redux, javascript, nodejs, express, sass, bem-methodology, nodemon, webpack, ecommerce, localstorage, axios, firebase\"/>\n    <meta name=\"description\" content=\"Simple ecommerce cart application built using React Redux\"/>\n    <meta name=\"reply-to\" content=\"jefferson.ribeiro.contato@gmail.com\"/>\n    <!--\n      manifest.json provides metadata used when your web app is added to the\n      homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"%PUBLIC_URL%/normalize.css\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/antd/3.10.7/antd.css\" />\n\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>React Shopping Cart</title>\n  </head>\n  <body>\n    <noscript>\n      You need to enable JavaScript to run this app.\n    </noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/public/normalize.css",
    "content": "/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS text size adjust after orientation change, without disabling\n *    user zoom.\n */\n\nhtml {\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability when focused and also mouse hovered in all browsers.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome\n *    (include `-moz` to future-proof).\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */ /* 2 */\n  box-sizing: content-box;\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/api/index.js",
    "content": "import config from '../config/server';\nimport axios from 'axios';\n\nexport function url(resource) {\n    if (!resource) {\n        return `${config.url}`\n    }\n    console.log(`${config.url}${config[resource]}`);\n    return `${config.url}${config[resource]}`\n}\nexport function setAuthToken(token) {\n    if (token) {\n        axios.defaults.headers.common['authorization'] = `${token}`;\n    } else {\n        delete axios.defaults.headers.common['authorization'];\n    }\n}\nexport function setGeoLocation(location) {\n    if (location) {\n        axios.defaults.headers.common['Location'] = `${location.lng},${location.lat}`;\n    } else {\n        delete axios.defaults.headers.common['Location'];\n    }\n}\nexport function getAuthToken() {\n    return localStorage.token;\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/App/index.js",
    "content": "import React, { Component } from 'react';\n\nimport Shelf from '../Shelf';\nimport Filter from '../Shelf/Filter';\nimport FloatCart from '../FloatCart';\n\nclass App extends Component {\n  render() {\n    return (\n      <React.Fragment>\n        <main>\n          <Filter />\n          <Shelf />\n        </main>\n        <FloatCart />\n      </React.Fragment>\n    );\n  }\n}\n\nexport default App;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Checkbox/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nclass Checkbox extends Component {\n  static propTypes = {\n    label: PropTypes.string.isRequired,\n    handleCheckboxChange: PropTypes.func.isRequired\n  };\n\n  state = {\n    isChecked: false\n  };\n\n  toggleCheckboxChange = () => {\n    const { handleCheckboxChange, label } = this.props;\n\n    this.setState(({ isChecked }) => ({\n      isChecked: !isChecked\n    }));\n\n    handleCheckboxChange(label);\n  };\n\n  render() {\n    const { label, classes } = this.props;\n    const { isChecked } = this.state;\n\n    return (\n      <div className={classes}>\n        <label>\n          <input\n            type=\"checkbox\"\n            value={label}\n            checked={isChecked}\n            onChange={this.toggleCheckboxChange}\n          />\n\n          <span className=\"checkmark\">{label}</span>\n        </label>\n      </div>\n    );\n  }\n}\n\nexport default Checkbox;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/FloatCart/CartProduct/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport Thumb from './../../Thumb';\nimport { formatPrice } from '../../../services/util';\n\nclass CartProduct extends Component {\n  static propTypes = {\n    product: PropTypes.object.isRequired,\n    removeProduct: PropTypes.func.isRequired\n  };\n\n  state = {\n    isMouseOver: false\n  };\n\n  handleMouseOver = () => {\n    this.setState({ isMouseOver: true });\n  };\n\n  handleMouseOut = () => {\n    this.setState({ isMouseOver: false });\n  };\n\n  render() {\n    const { product, removeProduct } = this.props;\n\n    const classes = ['shelf-item'];\n\n    if (!!this.state.isMouseOver) {\n      classes.push('shelf-item--mouseover');\n    }\n\n    return (\n      <div className={classes.join(' ')}>\n        <div\n          className=\"shelf-item__del\"\n          onMouseOver={() => this.handleMouseOver()}\n          onMouseOut={() => this.handleMouseOut()}\n          onClick={() => removeProduct(product)}\n        />\n        <Thumb\n          classes=\"shelf-item__thumb\"\n          src={require(`../../../static/products/${product.sku}_2.jpg`)}\n          alt={product.title}\n        />\n        <div className=\"shelf-item__details\">\n          <p className=\"title\">{product.title}</p>\n          <p className=\"desc\">\n            {`${product.availableSizes[0]} | ${product.style}`} <br />\n            Quantity: {product.quantity}\n          </p>\n        </div>\n        <div className=\"shelf-item__price\">\n          <p>{`${product.currencyFormat}  ${formatPrice(product.price)}`}</p>\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default CartProduct;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/FloatCart/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport { connect } from 'react-redux';\nimport { loadCart, removeProduct } from '../../services/cart/actions';\nimport { updateCart } from '../../services/total/actions';\nimport CartProduct from './CartProduct';\nimport { formatPrice } from '../../services/util';\n\nimport './style.scss';\n\nclass FloatCart extends Component {\n  static propTypes = {\n    loadCart: PropTypes.func.isRequired,\n    updateCart: PropTypes.func.isRequired,\n    cartProducts: PropTypes.array.isRequired,\n    newProduct: PropTypes.object,\n    removeProduct: PropTypes.func,\n    productToRemove: PropTypes.object\n  };\n\n  state = {\n    isOpen: false\n  };\n\n  componentWillReceiveProps(nextProps) {\n    if (nextProps.newProduct !== this.props.newProduct) {\n      this.addProduct(nextProps.newProduct);\n    }\n\n    if (nextProps.productToRemove !== this.props.productToRemove) {\n      this.removeProduct(nextProps.productToRemove);\n    }\n  }\n\n  openFloatCart = () => {\n    this.setState({ isOpen: true });\n  };\n\n  closeFloatCart = () => {\n    this.setState({ isOpen: false });\n  };\n\n  addProduct = product => {\n    const { cartProducts, updateCart } = this.props;\n    let productAlreadyInCart = false;\n\n    cartProducts.forEach(cp => {\n      if (cp.id === product.id) {\n        cp.quantity += product.quantity;\n        productAlreadyInCart = true;\n      }\n    });\n\n    if (!productAlreadyInCart) {\n      cartProducts.push(product);\n    }\n\n    updateCart(cartProducts);\n    this.openFloatCart();\n  };\n\n  removeProduct = product => {\n    const { cartProducts, updateCart } = this.props;\n\n    const index = cartProducts.findIndex(p => p.id === product.id);\n    if (index >= 0) {\n      cartProducts.splice(index, 1);\n      updateCart(cartProducts);\n    }\n  };\n\n  proceedToCheckout = () => {\n    const {\n      totalPrice,\n      productQuantity,\n      currencyFormat,\n      currencyId\n    } = this.props.cartTotal;\n\n    if (!productQuantity) {\n      alert('Add some product in the cart!');\n    } else {\n      alert(\n        `Checkout - Subtotal: ${currencyFormat} ${formatPrice(\n          totalPrice,\n          currencyId\n        )}`\n      );\n    }\n  };\n\n  render() {\n    const { cartTotal, cartProducts, removeProduct } = this.props;\n\n    const products = cartProducts.map(p => {\n      return (\n        <CartProduct product={p} removeProduct={removeProduct} key={p.id} />\n      );\n    });\n\n    let classes = ['float-cart'];\n\n    if (!!this.state.isOpen) {\n      classes.push('float-cart--open');\n    }\n\n    return (\n      <div className={classes.join(' ')}>\n        {/* If cart open, show close (x) button */}\n        {this.state.isOpen && (\n          <div\n            onClick={() => this.closeFloatCart()}\n            className=\"float-cart__close-btn\"\n          >\n            X\n          </div>\n        )}\n\n        {/* If cart is closed, show bag with quantity of product and open cart action */}\n        {!this.state.isOpen && (\n          <span\n            onClick={() => this.openFloatCart()}\n            className=\"bag bag--float-cart-closed\"\n          >\n            <span className=\"bag__quantity\">{cartTotal.productQuantity}</span>\n          </span>\n        )}\n\n        <div className=\"float-cart__content\">\n          <div className=\"float-cart__header\">\n            <span className=\"bag\">\n              <span className=\"bag__quantity\">{cartTotal.productQuantity}</span>\n            </span>\n            <span className=\"header-title\">Cart</span>\n          </div>\n\n          <div className=\"float-cart__shelf-container\">\n            {products}\n            {!products.length && (\n              <p className=\"shelf-empty\">\n                Add some products in the cart <br />\n                :)\n              </p>\n            )}\n          </div>\n\n          <div className=\"float-cart__footer\">\n            <div className=\"sub\">SUBTOTAL</div>\n            <div className=\"sub-price\">\n              <p className=\"sub-price__val\">\n                {`${cartTotal.currencyFormat} ${formatPrice(\n                  cartTotal.totalPrice,\n                  cartTotal.currencyId\n                )}`}\n              </p>\n              <small className=\"sub-price__installment\">\n                {!!cartTotal.installments && (\n                  <span>\n                    {`OR UP TO ${cartTotal.installments} x ${\n                      cartTotal.currencyFormat\n                    } ${formatPrice(\n                      cartTotal.totalPrice / cartTotal.installments,\n                      cartTotal.currencyId\n                    )}`}\n                  </span>\n                )}\n              </small>\n            </div>\n            <div onClick={() => this.proceedToCheckout()} className=\"buy-btn\">\n              Checkout\n            </div>\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n\nconst mapStateToProps = state => ({\n  cartProducts: state.cart.products,\n  newProduct: state.cart.productToAdd,\n  productToRemove: state.cart.productToRemove,\n  cartTotal: state.total.data\n});\n\nexport default connect(\n  mapStateToProps,\n  { loadCart, updateCart, removeProduct }\n)(FloatCart);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/FloatCart/style.scss",
    "content": ".float-cart {\n  position: fixed;\n  top: 0;\n  right: -450px;\n  width: 450px;\n  height: 100%;\n  background-color: #1b1a20;\n  box-sizing: border-box;\n\n  transition: right 0.2s;\n\n  &--open {\n    right: 0;\n  }\n\n  &__close-btn {\n    width: 50px;\n    height: 50px;\n    color: #ececec;\n    background-color: #1b1a20;\n    text-align: center;\n    line-height: 50px;\n    position: absolute;\n    top: 0;\n    left: -50px;\n    cursor: pointer;\n\n    &:hover {\n      background-color: #212027;\n    }\n  }\n\n  .bag {\n    width: 40px;\n    height: 40px;\n    position: relative;\n    display: inline-block;\n    vertical-align: middle;\n    margin-right: 15px;\n    background-image: url('../../static/bag-icon.png');\n    background-repeat: no-repeat;\n    background-size: contain;\n    background-position: center;\n\n    &--float-cart-closed {\n      position: absolute;\n      background-color: #000;\n      background-size: 50%;\n      left: -60px;\n      width: 60px;\n      height: 60px;\n      cursor: pointer;\n\n      .bag__quantity {\n        bottom: 5px;\n        right: 10px;\n      }\n    }\n\n    &__quantity {\n      display: inline-block;\n      width: 18px;\n      height: 18px;\n      color: #0c0b10;\n      font-weight: bold;\n      font-size: 0.7em;\n      text-align: center;\n      line-height: 18px;\n      border-radius: 50%;\n      background-color: #eabf00;\n      position: absolute;\n      bottom: -5px;\n      right: 0px;\n    }\n  }\n\n  &__header {\n    color: #ececec;\n    box-sizing: border-box;\n    text-align: center;\n    padding: 45px 0;\n\n    .header-title {\n      font-weight: bold;\n      font-size: 1.2em;\n      vertical-align: middle;\n    }\n  }\n\n  &__shelf-container {\n    position: relative;\n    min-height: 280px;\n    padding-bottom: 200px;\n\n    .shelf-empty {\n      color: #ececec;\n      text-align: center;\n      line-height: 40px;\n    }\n\n    .shelf-item {\n      position: relative;\n      box-sizing: border-box;\n      padding: 5%;\n\n      transition: background-color 0.2s, opacity 0.2s;\n\n      &::before {\n        content: '';\n        width: 90%;\n        height: 2px;\n        background-color: rgba(0, 0, 0, 0.2);\n        position: absolute;\n        top: 0;\n        left: 5%;\n      }\n\n      &--mouseover {\n        background: #0c0b10;\n\n        .shelf-item__details {\n          .title,\n          .desc {\n            text-decoration: line-through;\n            opacity: 0.6;\n          }\n        }\n\n        .shelf-item__price {\n          text-decoration: line-through;\n          opacity: 0.6;\n        }\n      }\n\n      &__del {\n        width: 16px;\n        height: 16px;\n        top: 15px;\n        right: 5%;\n        border-radius: 50%;\n        position: absolute;\n        background-size: auto 100%;\n        background-image: url('../../static/sprite_delete-icon.png');\n        background-repeat: no-repeat;\n        z-index: 2;\n        cursor: pointer;\n\n        &:hover {\n          background-position-x: -17px;\n        }\n      }\n\n      &__thumb,\n      &__details,\n      &__price {\n        display: inline-block;\n        vertical-align: middle;\n      }\n\n      &__thumb {\n        vertical-align: middle;\n        width: 15%;\n        margin-right: 3%;\n\n        img {\n          width: 100%;\n          height: auto;\n        }\n      }\n      &__details {\n        width: 57%;\n\n        .title {\n          color: #ececec;\n          margin: 0;\n        }\n\n        .desc {\n          color: #5b5a5e;\n          margin: 0;\n        }\n      }\n      &__price {\n        color: #eabf00;\n        text-align: right;\n        width: 25%;\n      }\n    }\n  }\n\n  &__footer {\n    box-sizing: border-box;\n    padding: 5%;\n    position: absolute;\n    bottom: 0;\n    width: 100%;\n    height: 200px;\n    z-index: 2;\n    background-color: #1b1a20;\n\n    &::before {\n      content: '';\n      width: 100%;\n      height: 20px;\n      display: block;\n      position: absolute;\n      top: -20px;\n      left: 0;\n      background: linear-gradient(to top, rgba(0, 0, 0, 0.2), transparent);\n    }\n\n    .sub,\n    .sub-price {\n      color: #5b5a5e;\n      vertical-align: middle;\n      display: inline-block;\n    }\n\n    .sub {\n      width: 20%;\n    }\n\n    .sub-price {\n      width: 80%;\n      text-align: right;\n\n      &__val,\n      &__installment {\n        margin: 0;\n      }\n\n      &__val {\n        color: #eabf00;\n        font-size: 22px;\n      }\n    }\n\n    .buy-btn {\n      color: #ececec;\n      text-transform: uppercase;\n      background-color: #0c0b10;\n      text-align: center;\n      padding: 15px 0;\n      margin-top: 40px;\n      cursor: pointer;\n\n      transition: background-color 0.2s;\n\n      &:hover {\n        background-color: #000;\n      }\n    }\n  }\n}\n\n/* MAC scrollbar para desktop*/\n@media screen and (min-width: 640px) {\n  .float-cart__content::-webkit-scrollbar {\n    -webkit-appearance: none;\n    width: 10px;\n    background-color: rgba(0, 0, 0, 0.2);\n    padding: 10px;\n  }\n  .float-cart__content::-webkit-scrollbar-thumb {\n    border-radius: 4px;\n    background-color: #0c0b10;\n  }\n}\n\n.float-cart__content {\n  height: 100%;\n  overflow-y: scroll;\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Selectbox/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nclass Selectbox extends Component {\n  static propTypes = {\n    options: PropTypes.array.isRequired,\n    classes: PropTypes.string,\n    handleOnChange: PropTypes.func.isRequired\n  };\n\n  state = {\n    selected: ''\n  };\n\n  createOptions = options =>\n    options.map(o => (\n      <option value={o.value} key={o.value}>\n        {o.label}\n      </option>\n    ));\n\n  onChange = e => {\n    this.props.handleOnChange(e.target.value);\n  };\n\n  render() {\n    const { classes, options } = this.props;\n\n    return (\n      <select onChange={e => this.onChange(e)} className={classes}>\n        {this.createOptions(options)}\n      </select>\n    );\n  }\n}\n\nexport default Selectbox;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/Filter/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport { connect } from 'react-redux';\nimport { updateFilters } from '../../../services/filters/actions';\nimport Checkbox from '../../Checkbox';\n\nimport './style.scss';\n\nconst availableSizes = ['XS', 'S', 'M', 'ML', 'L', 'XL', 'XXL'];\n\nclass Filter extends Component {\n  static propTypes = {\n    updateFilters: PropTypes.func.isRequired,\n    filters: PropTypes.array\n  };\n\n  componentDidMount() {\n    this.selectedCheckboxes = new Set();\n  }\n\n  toggleCheckbox = label => {\n    if (this.selectedCheckboxes.has(label)) {\n      this.selectedCheckboxes.delete(label);\n    } else {\n      this.selectedCheckboxes.add(label);\n    }\n\n    this.props.updateFilters(Array.from(this.selectedCheckboxes));\n  };\n\n  createCheckbox = label => (\n    <Checkbox\n      classes=\"filters-available-size\"\n      label={label}\n      handleCheckboxChange={this.toggleCheckbox}\n      key={label}\n    />\n  );\n\n  createCheckboxes = () => availableSizes.map(this.createCheckbox);\n\n  render() {\n    return (\n      <div className=\"filters\">\n        <h4 className=\"title\">Sizes:</h4>\n        {this.createCheckboxes()}\n      </div>\n    );\n  }\n}\n\nconst mapStateToProps = state => ({\n  filters: state.filters.items\n});\n\nexport default connect(\n  mapStateToProps,\n  { updateFilters }\n)(Filter);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/Filter/style.scss",
    "content": ".filters {\n  width: 15%;\n  margin-right: 15px;\n\n  .star-button-container {\n    text-align: center;\n    small {\n      color: #aaa;\n      margin-bottom: 8px;\n      display: inline-block;\n    }\n  }\n\n  .title {\n    margin-top: 2px;\n    margin-bottom: 20px;\n  }\n\n  &-available-size {\n    display: inline-block;\n    margin-bottom: 10px;\n    /* Customize the label (the container) */\n    label {\n      display: inline-block;\n      position: relative;\n      cursor: pointer;\n      font-size: 22px;\n      -webkit-user-select: none;\n      -moz-user-select: none;\n      -ms-user-select: none;\n      user-select: none;\n      width: 35px;\n      height: 35px;\n      font-size: 0.8em;\n      margin-bottom: 8px;\n      margin-right: 8px;\n      border-radius: 50%;\n      line-height: 35px;\n      text-align: center;\n\n      /* On mouse-over, add a grey background color */\n      &:hover input ~ .checkmark {\n        border: 1px solid #1b1a20;\n      }\n\n      /* When the checkbox is checked, add a blue background */\n      & input:checked ~ .checkmark {\n        background-color: #1b1a20;\n        color: #ececec;\n      }\n\n      /* Show the checkmark when checked */\n      & input:checked ~ .checkmark:after {\n        display: block;\n      }\n\n      input {\n        position: absolute;\n        opacity: 0;\n        cursor: pointer;\n      }\n\n      /* Create a custom checkbox */\n      .checkmark {\n        position: absolute;\n        top: 0;\n        left: 0;\n        width: 35px;\n        height: 35px;\n        font-size: 0.8em;\n        border-radius: 50%;\n        line-height: 35px;\n        text-align: center;\n        color: #1b1a20;\n        background-color: #ececec;\n\n        border: 1px solid transparent;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/ProductList/Product/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { connect } from 'react-redux';\n\nimport Thumb from '../../../Thumb';\nimport { formatPrice } from '../../../../services/util';\nimport { addProduct } from '../../../../services/cart/actions';\n\nconst Product = ({ product, addProduct }) => {\n  product.quantity = 1;\n\n  let formattedPrice = formatPrice(product.price, product.currencyId);\n\n  let productInstallment;\n\n  if (!!product.installments) {\n    const installmentPrice = product.price / product.installments;\n\n    productInstallment = (\n      <div className=\"installment\">\n        <span>or {product.installments} x</span>\n        <b>\n          {product.currencyFormat}\n          {formatPrice(installmentPrice, product.currencyId)}\n        </b>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      className=\"shelf-item\"\n      onClick={() => addProduct(product)}\n      data-sku={product.sku}\n    >\n      {product.isFreeShipping && (\n        <div className=\"shelf-stopper\">Free shipping</div>\n      )}\n      <Thumb\n        classes=\"shelf-item__thumb\"\n        src={require(`../../../../static/products/${product.sku}_1.jpg`)}\n        alt={product.title}\n      />\n      <p className=\"shelf-item__title\">{product.title}</p>\n      <div className=\"shelf-item__price\">\n        <div className=\"val\">\n          <small>{product.currencyFormat}</small>\n          <b>{formattedPrice.substr(0, formattedPrice.length - 3)}</b>\n          <span>{formattedPrice.substr(formattedPrice.length - 3, 3)}</span>\n        </div>\n        {productInstallment}\n      </div>\n      <div className=\"shelf-item__buy-btn\">Add to cart</div>\n    </div>\n  );\n};\n\nProduct.propTypes = {\n  product: PropTypes.object.isRequired,\n  addProduct: PropTypes.func.isRequired\n};\n\nexport default connect(\n  null,\n  { addProduct }\n)(Product);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/ProductList/index.js",
    "content": "import React from 'react';\n\nimport Product from './Product';\n\nconst ProductList = ({ products }) => {\n  return products.map(p => {\n    return <Product product={p} key={p.id} />;\n  });\n};\n\nexport default ProductList;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/ShelfHeader/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport Sort from '../Sort';\n\nconst ShelfHeader = props => {\n  return (\n    <div className=\"shelf-container-header\">\n      <small className=\"products-found\">\n        <span>{props.productsLength} Product(s) found.</span>\n      </small>\n      <Sort />\n    </div>\n  );\n};\n\nShelfHeader.propTypes = {\n  productsLength: PropTypes.number.isRequired\n};\n\nexport default ShelfHeader;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/Sort/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport { connect } from 'react-redux';\nimport { updateSort } from '../../../services/sort/actions';\nimport Selectbox from '../../Selectbox';\n\nconst sortBy = [\n  { value: '', label: 'Select' },\n  { value: 'lowestprice', label: 'Lowest to highest' },\n  { value: 'highestprice', label: 'Highest to lowest' }\n];\n\nclass Sort extends Component {\n  static propTypes = {\n    updateSort: PropTypes.func.isRequired,\n    sort: PropTypes.string.isRequired\n  };\n\n  handleSort = value => {\n    this.props.updateSort(value);\n  };\n\n  render() {\n    return (\n      <div className=\"sort\">\n        Order by\n        <Selectbox options={sortBy} handleOnChange={this.handleSort} />\n      </div>\n    );\n  }\n}\n\nconst mapStateToProps = state => ({\n  sort: state.sort.type\n});\n\nexport default connect(\n  mapStateToProps,\n  { updateSort }\n)(Sort);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { connect } from 'react-redux';\n\nimport { fetchProducts } from '../../services/shelf/actions';\n\nimport Spinner from '../Spinner';\nimport ShelfHeader from './ShelfHeader';\nimport ProductList from './ProductList';\n\nimport './style.scss';\n\nclass Shelf extends Component {\n  static propTypes = {\n    fetchProducts: PropTypes.func.isRequired,\n    products: PropTypes.array.isRequired,\n    filters: PropTypes.array,\n    sort: PropTypes.string\n  };\n\n  state = {\n    isLoading: false\n  };\n\n  componentDidMount() {\n    this.handleFetchProducts();\n  }\n\n  componentWillReceiveProps(nextProps) {\n    const { filters: nextFilters, sort: nextSort } = nextProps;\n\n    if (nextFilters !== this.props.filters) {\n      this.handleFetchProducts(nextFilters, undefined);\n    }\n\n    if (nextSort !== this.props.sort) {\n      this.handleFetchProducts(undefined, nextSort);\n    }\n  }\n\n  handleFetchProducts = (\n    filters = this.props.filters,\n    sort = this.props.sort\n  ) => {\n    this.setState({ isLoading: true });\n    this.props.fetchProducts(filters, sort, () => {\n      this.setState({ isLoading: false });\n    });\n  };\n\n  render() {\n    const { products } = this.props;\n    const { isLoading } = this.state;\n\n    return (\n      <React.Fragment>\n        {isLoading && <Spinner />}\n        <div className=\"shelf-container\">\n          <ShelfHeader productsLength={products.length} />\n          <ProductList products={products} />\n        </div>\n      </React.Fragment>\n    );\n  }\n}\n\nconst mapStateToProps = state => ({\n  products: state.shelf.products,\n  filters: state.filters.items,\n  sort: state.sort.type\n});\n\nexport default connect(\n  mapStateToProps,\n  { fetchProducts }\n)(Shelf);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Shelf/style.scss",
    "content": ".shelf-container {\n  display: flex;\n  flex-wrap: wrap;\n  width: 85%;\n  min-height: 600px;\n\n  &-header {\n    width: 100%;\n    margin-bottom: 10px;\n\n    .products-found {\n      float: left;\n      margin: 0;\n      margin-top: 8px;\n    }\n\n    .sort {\n      float: right;\n\n      select {\n        background-color: #fff;\n        outline: none;\n        border: 1px solid #ececec;\n        border-radius: 2px;\n        margin-left: 10px;\n        width: auto;\n        height: 35px;\n        cursor: pointer;\n\n        &:hover {\n          border: 1px solid #5b5a5e;\n        }\n      }\n    }\n  }\n\n  .shelf-item {\n    width: 25%;\n    position: relative;\n    text-align: center;\n    box-sizing: border-box;\n    padding: 10px;\n    margin-bottom: 30px;\n    border: 1px solid transparent;\n    cursor: pointer;\n\n    &:hover {\n      border: 1px solid #eee;\n\n      .shelf-item__buy-btn {\n        background-color: #eabf00;\n      }\n    }\n\n    .shelf-stopper {\n      position: absolute;\n      color: #ececec;\n      top: 10px;\n      right: 10px;\n      padding: 5px;\n      font-size: 0.6em;\n      background-color: #1b1a20;\n      cursor: default;\n    }\n\n    &__thumb {\n      img {\n        width: 100%;\n      }\n    }\n\n    &__title {\n      position: relative;\n      padding: 0 20px;\n      height: 45px;\n\n      &::before {\n        content: '';\n        width: 20px;\n        height: 2px;\n        background-color: #eabf00;\n        position: absolute;\n        bottom: 0;\n        left: 50%;\n        margin-left: -10px;\n      }\n    }\n\n    &__price {\n      height: 60px;\n\n      .val {\n        b {\n          font-size: 1.5em;\n          margin-left: 5px;\n        }\n      }\n\n      .installment {\n        color: #9c9b9b;\n      }\n    }\n\n    &__buy-btn {\n      background-color: #1b1a20;\n      color: #fff;\n      padding: 15px 0;\n      margin-top: 10px;\n      cursor: pointer;\n      // border-bottom: 2px solid #151419;\n\n      transition: background-color 0.2s;\n    }\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Spinner/index.js",
    "content": "import React from 'react';\n\nimport './style.scss';\n\nexport default () => (\n  <div className=\"spinner lds-ring\">\n    <div />\n    <div />\n    <div />\n    <div />\n  </div>\n);\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Spinner/style.scss",
    "content": ".spinner.lds-ring {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -32px;\n  margin-top: -32px;\n  width: 64px;\n  height: 64px;\n  z-index: 10;\n  border-radius: 5px;\n  background-color: #000;\n\n  div {\n    box-sizing: border-box;\n    display: block;\n    position: absolute;\n    width: 51px;\n    height: 51px;\n    margin: 6px;\n    border: 6px solid #fff;\n    border-radius: 50%;\n    animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n    border-color: #fff transparent transparent transparent;\n    &:nth-child(1) {\n      animation-delay: -0.45s;\n    }\n    &:nth-child(2) {\n      animation-delay: -0.3s;\n    }\n    &:nth-child(3) {\n      animation-delay: -0.15s;\n    }\n  }\n\n  @keyframes lds-ring {\n    0% {\n      transform: rotate(0deg);\n    }\n\n    100% {\n      transform: rotate(360deg);\n    }\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/components/Thumb/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst Thumb = props => {\n  return (\n    <div className={props.classes}>\n      <img src={props.src} alt={props.alt} title={props.title} />\n    </div>\n  );\n};\n\nThumb.propTypes = {\n  alt: PropTypes.string,\n  title: PropTypes.string,\n  classes: PropTypes.string,\n  src: PropTypes.string.isRequired\n};\n\nexport default Thumb;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/config/index.js",
    "content": "import server from '../config/server';\n\nexport default {\n\t// server: server\n\n\tsocial: {\n\t\tfacebook: server.url + 'auth/login/facebook',\n\t\tgoogle: server.url + 'auth/login/google',\n\t\ttwitter: server.url + 'auth/login/twitter',\n\t\tinstagram: server.url + 'auth/login/instagram',\n\t},\n\n\tgoogle: {\n\t\tapi_key: '***',\n\t},\n\n\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/config/server.js",
    "content": "export default {\n\turl: 'http://ms-commerce.com/api/v1/',\n\tregister: 'auth/register',\n\tlogin: 'auth/login',\n\tvalidate_auth: 'auth/validate',\n\treset_password: 'auth/reset-password',\n\tuserfetch : 'user/fetch',\n\tusers: 'users',\n\tuser : 'user',\n\tchangeRrole: 'user/change-role'\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/index.js",
    "content": "import React from 'react';\nimport {render} from 'react-dom';\nimport {\n\tRouter,\n\tRoute,\n\thashHistory,\n\tIndexRoute\n} from 'react-router';\n\nimport {notLoggedIn} from './util/middleware/index';\n\nimport { Provider } from 'react-redux';\n\nimport store from './services/store';\n// ------------------Login pages-------------------//\nimport RegisterPage from './services/auth/Register';\nimport LoginPage from './services/auth/Login';\nimport LogoutPage from './services/auth/Logout';\nimport ResetPasswordPage from './services/auth/ResetPassword';\nimport ValidateTokenPage from './services/auth/ValidateToken';\nimport AuthLayout from './layout/Auth';\n//------------------dashboard-------------------//\nimport PublicLayout from './layout/Public';\nimport PublicIndexPage from './components/App';\n\nrender((\n\t<Provider store={store()}>\n\t\t<Router history={hashHistory}>\n\t\t\t<Route path=\"/\" component={PublicLayout}  >\n\t\t\t\t<IndexRoute component={PublicIndexPage} />\n\t\t\t</Route>\n\t\t\t<Route path=\"auth\" component={AuthLayout} >\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"register\"\n\t\t\t\t\tcomponent={RegisterPage} onEnter={notLoggedIn}\n\t\t\t\t/>\n\t\t\t\t<Route path=\"login\" component={LoginPage} onEnter={notLoggedIn} />\n\t\t\t\t<Route path=\"logout\" component={LogoutPage} />\n\t\t\t\t<Route path=\"validate-token\" component={ValidateTokenPage} />\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"reset-password\"\n\t\t\t\t\tcomponent={ResetPasswordPage}\n\t\t\t\t\tonEnter={notLoggedIn} />\n\t\t\t</Route>\n\t\t</Router>\n\t</Provider>\n), document.getElementById(\"root\"));\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/index.scss",
    "content": "@import url('https://fonts.googleapis.com/css?family=Roboto');\n\nbody {\n  margin: 0;\n  padding: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\nbody {\n  margin: 0;\n  color: #1b1a20;\n  font-family: 'Roboto', sans-serif;\n}\n\nmain {\n  display: flex;\n  padding: 20px 2%;\n  max-width: 1200px;\n  margin: 50px auto 0 auto;\n}\n\n@media only screen and (max-width: 1024px) {\n  body {\n    .filters {\n      width: 20%;\n    }\n\n    .shelf-container {\n      width: 80%;\n\n      .shelf-item {\n        width: 33.33%;\n      }\n    }\n  }\n}\n\n@media only screen and (max-width: 640px) {\n  body {\n    .filters {\n      width: 25%;\n    }\n\n    .shelf-container {\n      width: 75%;\n\n      .shelf-item {\n        width: 50%;\n        padding: 10px;\n\n        &__title {\n          margin-top: 5px;\n          padding: 0;\n        }\n      }\n    }\n\n    .float-cart {\n      width: 100%;\n      right: -100%;\n\n      &--open {\n        right: 0;\n      }\n\n      &__close-btn {\n        left: 0px;\n        z-index: 2;\n        background-color: #1b1a20;\n      }\n\n      &__header {\n        padding: 25px 0;\n      }\n    }\n  }\n}\n\n@media only screen and (max-width: 460px) {\n  body {\n    main {\n      display: flex;\n      flex-wrap: wrap;\n      padding: 2%;\n      margin-top: 42px;\n    }\n\n    .filters {\n      width: 100%;\n      margin-right: 0;\n      text-align: center;\n\n      .title {\n        margin-bottom: 15px;\n      }\n    }\n\n    .shelf-container-header {\n      .products-found {\n        width: 100%;\n        text-align: center;\n        margin: 10px 0;\n      }\n\n      .sort {\n        width: 100%;\n        text-align: center;\n      }\n    }\n\n    .shelf-container {\n      width: 100%;\n\n      .shelf-item {\n        width: 50%;\n\n        &__buy-btn {\n          display: none;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/layout/Auth.js",
    "content": "import React from 'react';\nlet AuthLayout = (props) => {\n\n\tlet backgroundChoices = ['bg1', 'bg4', 'bg3', 'bg4', 'bg5'];\n\n\tlet background_image;\n\tdelete localStorage.auth_background;\n\tif (!localStorage.auth_background) {\n\t\tbackground_image = backgroundChoices[Math.floor(Math.random() * backgroundChoices.length)];\n\t\tlocalStorage.auth_background = background_image;\n\t} else {\n\t\tbackground_image = localStorage.auth_background;\n\t}\n\n\treturn (\n\t\t\t<div className={`auth-container ${background_image}`}>\n\t\t\t\t{props.children}\n\t\t\t</div>\n\t)\n\n}\n\nexport default AuthLayout;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/layout/Public.js",
    "content": "import React, {Component} from 'react';\nimport axios from 'axios';\nimport * as API from '../api/index';\nimport {message} from 'antd';\nimport Auth from '../util/middleware/auth';\nimport {connect} from 'react-redux';\nimport * as Action from '../services/auth/action';\n\nconst mapStateToProps = (state, ownProps) => {\n\treturn {\n\t\tuser: state.auth.get('user')\n\t\t}\n}\nconst mapDispatchToProps = (dispatch, ownProps) => {\n\treturn {\n\t\tauthUpdateUserData: (data) => dispatch(Action.authUpdateUserData(data))\n\t\t}\n}\n\nclass PublicPage extends Component {\n\n\tconstructor(props) {\n\t\tsuper(props);\n\t\tlet access_token = Auth.getAccessToken()\n\t\tif (access_token) {\n\t\t\tAPI.setAuthToken(access_token);\n\t\t\taxios.get(API.url('validate_auth'))\n\t\t\t\t.then((response) => {\n\t\t\t\t\tconst user = response.data.user;\n\t\t\t\t\tif (response.data.statusCode === 200 && response.data.success === true) {\n\t\t\t\t\t\tAuth.setAccessToken(access_token);\n\t\t\t\t\t\tthis.props.authUpdateUserData(response.data.user);\n\t\t\t\t\t\tconsole.log(response.data.user);\n\t\t\t\t\t\tthis.loadUserProfile(user.email);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmessage.error('Invalid auth token, please try logging in again', 3);\n\t\t\t\t\t\tAuth.deleteAccessToken();\n\t\t\t\t\t\tAPI.setAuthToken();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch((response) => {\n\t\t\t\t\tconsole.log('catch error', response);\n\t\t\t\t});\n\t\t}\n\t}\n\trender() {\n\t\treturn (\n\t\t\t<div>\n            {this.props.children}\n\t\t   </div>\n\t\t)\n\t}\n}\n\nconst PublicRoutePage = connect(mapStateToProps, mapDispatchToProps)(PublicPage);\n\nexport default PublicRoutePage;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/Login.js",
    "content": "import React from 'react'\nimport { connect } from 'react-redux'\nimport * as Action from './action'\nimport { Link } from 'react-router'\nimport { Spin, Alert } from 'antd'\nimport Util from '../../util/helper/index';\nimport config from '../../config/index';\nconst mapStateToProps = (state, ownProps) => {\n  return {\n    status: state.auth.get('status'),\n    login: state.auth.get('login')\n  }\n}\nconst mapDispatchToProps = (dispatch, ownProps) => {\n  return {\n    authSubmitLoginForm: status => dispatch(Action.authSubmitLoginForm(status)),\n    authInvalidateLoginForm: value =>\n      dispatch(Action.authInvalidateLoginForm(value)),\n    authUpdateLoginFormField: data =>\n      dispatch(Action.authUpdateLoginFormField(data)),\n    authServerLoginUser: value => dispatch(Action.authServerLoginUser(value))\n  }\n}\n\nlet LoginPage = props => {\n  let user_email = props.login.get('email')\n  console.log(user_email + 'user email');\n  let user_password = props.login.get('password')\n\n  let handleSubmit = event => {\n    event.preventDefault()\n    props.authSubmitLoginForm(true)\n\n    let errorHandler = (message, description) => {\n      setTimeout(() => {\n        //notification.error({message: message, description: description});\n        props.authInvalidateLoginForm(true)\n        props.authSubmitLoginForm(false)\n      }, 50)\n    }\n\n    if (!user_email || !user_password) {\n      errorHandler(\n        'Error Occoured!',\n        'Please enter your email address and password.'\n      )\n    } else if (!Util.validateEmail(user_email)) {\n      errorHandler('Invalid Email', 'Please enter a valid email address.')\n    } else {\n      props.authInvalidateLoginForm(false)\n      props.authServerLoginUser({ email: user_email, password: user_password })\n    }\n  }\n\n  let handleInputChange = (event, field) => {\n    let value = event.target.value\n    props.authUpdateLoginFormField({ field, value })\n  }\n\n  const uiLinks = (\n    <div className=\"social social-btn\">\n      <a href={config.social.facebook} className=\"btn btn-default button block facebook\">\n        <i className=\"fa fa-facebook-official\" aria-hidden=\"true\" />\n        Login with Facebook\n      </a>\n      <a href={config.social.google} className=\"btn btn-default button block google\">\n        <i className=\"fa fa-google\" aria-hidden=\"true\" />\n        Login with Google\n      </a>\n    </div>\n  )\n\n  return (\n    <div className=\"scooty-bg-image\">\n      <div className=\"scooty-form\">\n        <div className=\"container\">\n          <div className=\"row \">\n            <div className=\"offset-xl-3 col-xl-6 offset-lg-3 col-lg-6 col-md-12 col-sm-12 col-12  \">\n              <div className=\"scooty-head\">\n                <Link to=\"/\"><img src=\"images/logo.png\" className=\"auth-logo\" alt=\"\" /></Link>\n              </div>\n              <div className=\"st-tab\">\n                <ul\n                  className=\"nav nav-tabs nav-justified\"\n                  id=\"Mytabs\"\n                  role=\"tablist\">\n                  <li className=\"nav-item\">\n                    <a\n                      className=\"nav-link\"\n                      id=\"tab-2\"\n                      data-toggle=\"tab\"\n                      href=\"#tab2\"\n                      role=\"tab\"\n                      aria-controls=\"tab-2\"\n                      aria-selected=\"false\">\n                      Login\n                    </a>\n                  </li>\n                </ul>\n                <div className=\"tab-content\" id=\"myTabContent\">\n                  <div\n                    className=\"tab-pane active\"\n                    id=\"tab2\"\n                    role=\"tabpanel\"\n                    aria-labelledby=\"tab-2\">\n                    <div className=\"container\">\n                      <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n                        <h3>Sign In to Your Account</h3>\n                        <p>\n                          Sign in to find best rental scooty\n                        </p>\n                        {props.login.get('error') && <Alert message=\"Please enter valid email and password.\" type=\"error\" showIcon=\"false\" />}\n                        <Spin spinning={props.login.get('submit')} size=\"large\">\n                          <form onSubmit={handleSubmit}>\n                            <div className=\"row\">\n                              <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n                                <div className=\"form-group\">\n                                  <label\n                                    className=\"control-label sr-only\"\n                                    htmlFor=\"username\"\n                                  />\n                                  <input\n                                    id=\"username\"\n                                    type=\"text\"\n                                    name=\"username\"\n                                    placeholder=\"User Name\"\n                                    className=\"form-control\"\n                                    autoFocus\n                                    defaultValue={user_email}\n                                    onChange={e => {\n                                      handleInputChange(e, 'email')\n                                    }}\n                                  />\n                                </div>\n                              </div>\n                              <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n                                <div className=\"form-group service-form-group\">\n                                  <label\n                                    className=\"control-label sr-only\"\n                                    htmlFor=\"passwordlogin\"\n                                  />\n                                  <input\n                                    id=\"passwordlogin\"\n                                    type=\"password\"\n                                    name=\"passwordlogin\"\n                                    placeholder=\"Password\"\n                                    className=\"form-control\"\n                                    defaultValue={user_password}\n                                    onChange={e => {\n                                      handleInputChange(e, 'password')\n                                    }}\n                                  />\n                                </div>\n                              </div>\n                              <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n                                <button\n                                  type=\"submit\"\n                                  name=\"singlebutton\"\n                                  className=\"btn btn-default\">\n                                  Login\n                              </button>\n                              </div>\n                            </div>\n                          </form>\n                        </Spin>\n                        <p className=\"mt-2\">\n                          Are you new here? Create a New Account.\n                          <Link to=\"/auth/register\"> Click here</Link>\n                        </p>\n                        <p className=\"mt-2\">\n                          forgot password\n                          <Link to=\"/auth/reset-password\"> Click here</Link>\n                        </p>\n                        {uiLinks}\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  )\n}\n\nconst ConnectLoginPage = connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(LoginPage)\n\nexport default ConnectLoginPage\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/Logout.js",
    "content": "\n  import React from 'react';\n\timport { Link } from 'react-router';\n\timport { connect } from 'react-redux';\n\timport * as Action from './action';\n\n\timport Auth from '../../util/middleware/auth';\n\timport { message } from 'antd';\n\n\tconst mapStateToProps = ( state, ownProps ) => {\n\t\treturn {\n\t\t\tuser: state.auth.get('user'),\n\t\t}\n\t}\n\n\tconst mapDispatchToProps = ( dispatch, ownProps ) => {\n\t\treturn {\n\t\t\tauthResetUserData: () => dispatch( Action.authResetUserData() ),\n\t\t\treduxResetState: () => dispatch( Action.reduxResetState() ),\n\n\t\t}\n\t}\n\n\tlet LogoutPage = (props) => {\n\t\tif ( props.user.size > 0 ) {\n\t\t\tsetTimeout( () => {\n\t\t\t\tAuth.logout();\n\t\t\t\tprops.authResetUserData();\n\t\t\t\tprops.reduxResetState();\n\t\t\t\tmessage.info('You have been successfully logged out', 3);\n\t\t\t}, 20 );\n\t\t}\n\t\tconst ui_message_logout = (\n\t\t\t<div className=\"content\">\n\t\t\t\t<h3>Logging you out right now...</h3>\n\t\t\t\t<p className=\"m-t-10\">please be patient.</p>\n\t\t\t</div>\n\t\t);\n\n\t\tconst ui_message_done = (\n\t\t\t<div className=\"content\">\n\t\t\t\t<h5>You have been successfully logged out.</h5>\n\t\t\t\t<Link  to=\"/auth/login\" className=\"button default inline m-t-20 label-marker\">Login Again &rarr;</Link>\n\t\t\t</div>\n\t\t);\n\n\t\treturn (\n\n\t\t\t<div className=\"scooty-bg-image\">\n\t\t\t<div className=\"scooty-form\">\n\t\t\t  <div className=\"container\">\n\t\t\t\t<div className=\"row \">\n\t\t\t\t  <div className=\"offset-xl-3 col-xl-6 offset-lg-3 col-lg-6 col-md-12 col-sm-12 col-12  \">\n\t\t\t\t\t<div className=\"scooty-head\">\n\t\t\t\t\t\t\t  <Link to=\"/\"><img src=\"images/logo.png\" className=\"auth-logo\" alt=\"\"/></Link>\n\t\t\t\t\t  </div>\n\t\t\t\t\t<div className=\"st-tab\">\n\t\t\t\t\t  <div className=\"tab-content\" id=\"myTabContent\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t  className=\"tab-pane active\"\n\t\t\t\t\t\t  id=\"tab2\"\n\t\t\t\t\t\t  role=\"tabpanel\"\n\t\t\t\t\t\t  aria-labelledby=\"tab-2\">\n\t\t\t\t\t\t  <div className=\"container\">\n\t\t\t\t\t\t\t<div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t  { props.user.get('id') ? ui_message_logout : ui_message_done }\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t  </div>\n\t\t\t\t\t</div>\n\t\t\t\t  </div>\n\t\t\t\t</div>\n\t\t\t  </div>\n\t\t\t</div>\n\t\t  </div>\n\t\t)\n\n\t}\n\n\tconst ConnectLogoutPage = connect(\n\t\tmapStateToProps,\n\t\tmapDispatchToProps\n\t)(LogoutPage)\n\n\texport default ConnectLogoutPage;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/Register.js",
    "content": "import React from 'react'\nimport { connect } from 'react-redux'\nimport * as Action from './action'\nimport { Link } from 'react-router'\nimport { Spin, Alert, notification } from 'antd'\nimport Util from '../../util/helper/index';\nconst mapStateToProps = (state, ownProps) => {\n  return {\n    register: state.auth.get('register')\n  }\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n  return {\n    authSubmitRegisterForm: status =>\n      dispatch(Action.authSubmitRegisterForm(status)),\n    authUpdateRegisterFormField: data =>\n      dispatch(Action.authUpdateRegisterFormField(data)),\n    authInvalidateRegisterForm: value =>\n      dispatch(Action.authInvalidateRegisterForm(value)),\n    authServerRegisterUser: value =>\n      dispatch(Action.authServerRegisterUser(value))\n  }\n}\n\nlet RegisterPage = props => {\n  // get data from state and assign\n  //\n  let user_name = props.register.get('username')\n  let user_email = props.register.get('email')\n  let user_password = props.register.get('password')\n  let user_password_confirm = props.register.get('password_confirm')\n\n  let handleSubmit = event => {\n    event.preventDefault()\n    props.authSubmitRegisterForm(true)\n\n    let errorHandler = (message, description) => {\n      setTimeout(() => {\n        notification.error({ message: message, description: description })\n        props.authInvalidateRegisterForm(true)\n        props.authSubmitRegisterForm(false)\n      }, 50)\n\t\t}\n    if (!user_name || !user_email || !user_password || !user_password_confirm) {\n      errorHandler('Error Occoured!', 'Please enter all the fields.')\n    } else if (!Util.validateEmail(user_email)) {\n      errorHandler('Invalid Email', 'Please enter a valid email address.')\n    } else if (user_password !== user_password_confirm) {\n      errorHandler(\n        'Password Mismatch',\n        'Your password and verify password is not same.'\n      )\n    } else if (user_password.length <= 6) {\n      errorHandler(\n        'Password length',\n        'Your password should have minimum 6 Character.'\n      )\n    } else {\n      props.authInvalidateRegisterForm(false)\n      props.authServerRegisterUser({\n        username: user_name,\n        email: user_email,\n        address: null,\n        password: user_password,\n        verify_password: user_password_confirm\n      })\n    }\n  }\n\n  let handleInputChange = (event, field) => {\n    let value = event.target.value\n    props.authUpdateRegisterFormField({ field, value })\n\t}\n\n  return (\n\t<div className=\"scooty-bg-image\">\n\t<div className=\"scooty-form\">\n\t  <div className=\"container\">\n\t\t<div className=\"row \">\n\t\t  <div className=\"offset-xl-3 col-xl-6 offset-lg-3 col-lg-6 col-md-12 col-sm-12 col-12  \">\n\t\t\t<div className=\"scooty-head\">\n\t\t\t\t\t  <Link to=\"/\"><img src=\"images/logo.png\" className=\"auth-logo\" alt=\"\"/></Link>\n\t\t\t  </div>\n\t\t\t<div className=\"st-tab\">\n\t\t\t  <ul\n\t\t\t\tclassName=\"nav nav-tabs nav-justified\"\n\t\t\t\tid=\"Mytabs\"\n\t\t\t\trole=\"tablist\">\n\t\t\t\t<li className=\"nav-item\">\n\t\t\t\t  <a\n\t\t\t\t\tclassName=\"nav-link\"\n\t\t\t\t\tid=\"tab-2\"\n\t\t\t\t\tdata-toggle=\"tab\"\n\t\t\t\t\thref=\"#tab2\"\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\taria-controls=\"tab-2\"\n\t\t\t\t\taria-selected=\"false\">\n\t\t\t\t\tRegister\n\t\t\t\t  </a>\n\t\t\t\t</li>\n\t\t\t  </ul>\n\t\t\t  <div className=\"tab-content\" id=\"myTabContent\">\n\t\t\t\t<div\n\t\t\t\t  className=\"tab-pane active\"\n\t\t\t\t  id=\"tab2\"\n\t\t\t\t  role=\"tabpanel\"\n\t\t\t\t  aria-labelledby=\"tab-2\">\n\t\t\t\t  <div className=\"container\">\n\t\t\t\t\t<div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t  <h3>Sign In to Your Account</h3>\n\t\t\t\t\t  <p>\n\t\t\t\t\t\tSign in to find best rental scooty\n\t\t\t\t\t  </p>\n\t\t\t\t\t  <Spin spinning={props.register.get('submit')} size=\"large\">\n\t\t\t\t\t  <form onSubmit={handleSubmit}>\n\t\t\t\t\t  {props.register.get('error') && (\n\t\t\t\t\t\t<Alert\n\t\t\t\t\t\t\tmessage=\"Place enter all the fields with valid information.\"\n\t\t\t\t\t\t\ttype=\"error\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<div className=\"row\">\n\t\t\t\t\t\t  <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t<div className=\"form-group\">\n\t\t\t\t\t\t\t  <label\n\t\t\t\t\t\t\t\tclassName=\"control-label sr-only\"\n\t\t\t\t\t\t\t\thtmlFor=\"username\"\n\t\t\t\t\t\t\t  />\n\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tplaceholder=\"full name\"\n\t\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\t\tclassName=\"form-control\"\n\t\t\t\t\t\t\t\t\tdefaultValue={user_name}\n\t\t\t\t\t\t\t\t\tonChange={e => {\n\t\t\t\t\t\t\t\t\thandleInputChange(e, 'username')\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t  <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t<div className=\"form-group service-form-group\">\n\t\t\t\t\t\t\t  <label\n\t\t\t\t\t\t\t\tclassName=\"control-label sr-only\"\n\t\t\t\t\t\t\t\thtmlFor=\"email\"\n\t\t\t\t\t\t\t  />\n\t\t\t\t\t\t\t   <input\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tclassName=\"form-control\"\n\t\t\t\t\t\t\t\t\tplaceholder=\"email address\"\n\t\t\t\t\t\t\t\t\tdefaultValue={user_email}\n\t\t\t\t\t\t\t\t\tonChange={e => {\n\t\t\t\t\t\t\t\t\thandleInputChange(e, 'email')\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t  <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t<div className=\"form-group service-form-group\">\n\t\t\t\t\t\t\t  <label\n\t\t\t\t\t\t\t\tclassName=\"control-label sr-only\"\n\t\t\t\t\t\t\t\thtmlFor=\"password\"\n\t\t\t\t\t\t\t  />\n\t\t\t\t\t\t\t   <input\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\tclassName=\"form-control\"\n\t\t\t\t\t\t\t\t\tplaceholder=\"password\"\n\t\t\t\t\t\t\t\t\tdefaultValue={user_password}\n\t\t\t\t\t\t\t\t\tonChange={e => {\n\t\t\t\t\t\t\t\t\thandleInputChange(e, 'password')\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t  <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t<div className=\"form-group service-form-group\">\n\t\t\t\t\t\t\t  <label\n\t\t\t\t\t\t\t\tclassName=\"control-label sr-only\"\n\t\t\t\t\t\t\t\thtmlFor=\"password\"\n\t\t\t\t\t\t\t  />\n\t\t\t\t\t\t\t   <input\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\tplaceholder=\"verify password\"\n\t\t\t\t\t\t\t\t\tclassName=\"form-control\"\n\t\t\t\t\t\t\t\t\tdefaultValue={user_password_confirm}\n\t\t\t\t\t\t\t\t\tonChange={e => {\n\t\t\t\t\t\t\t\t\thandleInputChange(e, 'password_confirm')\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t  <div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t  type=\"submit\"\n\t\t\t\t\t\t\t  name=\"singlebutton\"\n\t\t\t\t\t\t\t  className=\"btn btn-default\">\n\t\t\t\t\t\t\t  Register\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t  </form>\n\t\t\t\t\t  </Spin>\n\t\t\t\t\t  <p className=\"mt-2\">\n\t\t\t\t\t\tAre you new here? Create a New Account.\n\t\t\t\t\t\t<Link to=\"/auth/login\"> Click here</Link>\n\t\t\t\t\t  </p>\n\t\t\t\t\t</div>\n\t\t\t\t  </div>\n\t\t\t\t</div>\n\t\t\t  </div>\n\t\t\t</div>\n\t\t  </div>\n\t\t</div>\n\t  </div>\n\t</div>\n  </div>\n  )\n}\n\nconst ConnectLoginPage = connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(RegisterPage)\n\nexport default ConnectLoginPage\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/ResetPassword.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport * as Action from './action';\nimport { Link } from 'react-router';\nimport { Spin, Alert, notification } from 'antd';\nimport InputHelper from '../../util/helper/index';\nconst mapStateToProps = (state, ownProps) => {\n\treturn {\n\t\tlogin: state\n\t\t\t.auth\n\t\t\t.get('login'),\n\t\treset_password: state\n\t\t\t.auth\n\t\t\t.get('reset_password')\n\t}\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n\treturn {\n\t\tauthUpdateLoginFormField: (data) => dispatch(Action.authUpdateLoginFormField(data)),\n\t\tauthSubmitResetPasswordForm: (data) => dispatch(Action.authSubmitResetPasswordForm(data)),\n\t\tauthInvalidateResetPasswordForm: (data) => dispatch(Action.authInvalidateResetPasswordForm(data)),\n\t\tauthServerResetPassword: (data) => dispatch(Action.authServerResetPassword(data))\n\t}\n}\n\nlet ResetPasswordPage = (props) => {\n\n\tlet user_email = props\n\t\t.login\n\t\t.get('email');\n\n\tlet handleSubmit = (event) => {\n\t\tevent.preventDefault();\n\t\tprops.authSubmitResetPasswordForm(true);\n\n\t\tlet errorHandler = (message, description) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tprops.authInvalidateResetPasswordForm(true);\n\t\t\t\tnotification.error({ message: message, description: description });\n\t\t\t\tprops.authSubmitResetPasswordForm(false);\n\t\t\t}, 50);\n\t\t}\n\n\t\tif (!user_email) {\n\t\t\terrorHandler('Error Occoured!', 'Please enter your email address.')\n\t\t} else if (!InputHelper.validateEmail(user_email)) {\n\t\t\terrorHandler('Invalid Email', 'Please enter a valid email address.')\n\t\t} else {\n\t\t\tprops.authInvalidateResetPasswordForm(false);\n\t\t\tprops.authServerResetPassword({ email: user_email });\n\t\t}\n\n\t}\n\n\tlet handleInputChange = (event, field) => {\n\t\tlet value = event.target.value;\n\t\tprops.authUpdateLoginFormField({ field, value });\n\t}\n\n\treturn (\n\t\t<div className=\"scooty-bg-image\">\n\t\t\t<div className=\"scooty-form\">\n\t\t\t\t<div className=\"container\">\n\t\t\t\t\t<div className=\"row \">\n\t\t\t\t\t\t<div className=\"offset-xl-3 col-xl-6 offset-lg-3 col-lg-6 col-md-12 col-sm-12 col-12  \">\n\t\t\t\t\t\t\t<div className=\"scooty-head\">\n\t\t\t\t\t\t\t\t<Link to=\"/\"><img src=\"images/logo.png\" className=\"auth-logo\" alt=\"\" /></Link>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t<div className=\"container\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t\t\t\t\t\t<h3>Reset Account Password</h3>\n\t\t\t\t\t\t\t\t\t\t\t\t{props.reset_password.get('error') && <Alert message=\"Place enter valid email information\" type=\"error\" showIcon />}\n\t\t\t\t\t\t\t\t\t\t\t\t<Spin spinning={props.reset_password.get('submit')} size=\"large\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<form onSubmit={handleSubmit}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"row\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"form-group\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"control-label sr-only\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thtmlFor=\"email\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid=\"username\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"email\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tplaceholder=\"email\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"form-control\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdefaultValue={user_email}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonChange={e => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thandleInputChange(e, 'email')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{props\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.reset_password\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.get('done') && <h6>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p>Password reset request received. If your email is registered with us, you\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twill receive a password reset email.</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p>You can alternatively &nbsp;&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link to=\"/auth/login\">login with your social profile</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;&nbsp; as well.</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</h6>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 \">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"singlebutton\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"btn btn-default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tReset Password\n\t\t\t\t\t\t\t\t\t               </button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</form>\n\t\t\t\t\t\t\t\t\t\t\t\t</Spin>\n\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"mt-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t\tAre you new here? Create a New Account.\n\t\t\t\t\t\t\t\t <Link to=\"/auth/register\"> Click here</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t)\n}\n\nconst ConnectResetPasswordPage = connect(mapStateToProps, mapDispatchToProps)(ResetPasswordPage)\n\nexport default ConnectResetPasswordPage;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/ValidateToken.js",
    "content": "import React from 'react';\nimport {connect} from 'react-redux';\nimport * as Action from './action';\nimport {Link, hashHistory} from 'react-router';\nimport {message, Spin} from 'antd';\n\nimport * as API from '../../api'\nimport Auth from '../../util/middleware/auth';\nimport axios from 'axios';\nimport jwt from 'jsonwebtoken';\n\nconst mapStateToProps = (state, ownProps) => {\n\treturn {query: ownProps.location.query}\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n\treturn {\n\t\tauthUpdateUserData: (data) => dispatch(Action.authUpdateUserData(data))\n\t}\n}\n\nlet ValidateTokenPage = (props) => {\n\n\tconst access_token = props.query.token;\n\tconsole.log(access_token);\n\tif (access_token) {\n\t\tAPI.setAuthToken(access_token);\n\t\taxios\n\t\t.get(API.url('validate_auth'))\n\t\t.then((response) => {\n\t\t\tif (response.data.statusCode === 200 && response.data.success === true) {\n\t\t\t\tmessage.success('Successfully logged in.', 3);\n\t\t\t\tAuth.setAccessToken(access_token);\n\t\t\t\tconst userToken = jwt.decode(access_token);\n\t\t\t\tprops.authUpdateUserData(userToken);\n\n\t\t\t\tif(userToken.type === '1'){\n\t\t\t\t//\thashHistory.push(routes.user_dashboard);\n\t\t\t\t} else {\n\t\t\t\t//\thashHistory.push(routes.vendor_dashboard);\n\t\t\t\t}\n\n\n\t\t\t} else {\n\t\t\t\tmessage.error('Invalid auth token, please try logging in again', 3);\n\t\t\t\tAuth.deleteAccessToken();\n\t\t\t\tAPI.setAuthToken();\n\t\t\t\thashHistory.push('/auth/login');\n\t\t\t}\n\t\t})\n\t\t.catch((response) => {\n\t\t\tconsole.log('catch error', response);\n\t\t});\n\n\t}\n\n\tconst ui_logo = (\n\t     \t<Link to=\"/\"><img src=\"images/logo.png\" className=\"auth-logo\" alt=\"\"/></Link>\n\t);\n\n\tconst ui_no_access_token = (\n\t\t<div className=\"content\">\n\t\t<h1>Access token not present</h1>\n\t\t<Link\n\t\tto=\"/auth/login\"\n\t\tclassName=\"button default inline m-t-20 label-marker\">Try logging in again &rarr;</Link>\n\t\t</div>\n\t);\n\n\tconst ui_verifying = (\n\t\t<div className=\"content\">\n\t\t<h4>Verifying your account, Please wait...</h4>\n\t\t<div className=\"m-t-20 center\">\n\t\t<Spin size=\"large\"/>\n\t\t</div>\n\t\t</div>\n\t);\n\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"scooty-head\">\n\t\t\t{ui_logo}\n\t\t\t{access_token\n\t\t\t\t? ui_verifying\n\t\t\t\t: ui_no_access_token}\n\t\t\t</div>\n\t\t</div>\n\t\t)\n\n\t}\n\n\tconst ConnectValidateTokenPage = connect(mapStateToProps, mapDispatchToProps)(ValidateTokenPage)\n\n\texport default ConnectValidateTokenPage;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/action.js",
    "content": "import {\n  REDUX_RESET_STATE,\n  AUTH_UPDATE_REGISTER_FORM_FIELD,\n  AUTH_SUBMIT_REGISTER_FORM,\n  AUTH_INVALIDATE_REGISTER_FORM,\n  AUTH_RESET_REGISTER_FORM_FIELDS,\n  AUTH_UPDATE_USER_DATA,\n  AUTH_RESET_USER_DATA,\n  AUTH_UPDATE_USER_FIELD,\n  AUTH_UPDATE_LOGIN_FORM_FIELD,\n  AUTH_SUBMIT_LOGIN_FORM,\n  AUTH_INVALIDATE_LOGIN_FORM,\n  AUTH_RESET_LOGIN_FORM_FIELDS,\n  AUTH_SUBMIT_RESET_PASSWORD_FORM,\n  AUTH_UPDATE_RESET_PASSWORD_STATUS_FIELD,\n  AUTH_INVALIDATE_RESET_PASSWORD_FORM,\n  USER_UPDATE_PROFILE,\n\tUSER_UPDATE_PROFILE_FIELD,\n\tUSER_DELETE_PROFILE_FIELD,\n  USER_PROFILE_LOADED,\n  UPDATE_FIELD,\n  UPDATE_SECTION,\n  UPDATE_TABS,\n  UPDATE_LOADED\n} from \"./actionTypes\";\n\n\n\n\nimport axios from \"axios\";\nimport * as API from \"../../api/index\";\nimport { message, notification } from \"antd\";\nimport Auth from \"../../util/middleware/auth\";\nimport jwt from \"jsonwebtoken\";\nimport { hashHistory } from \"react-router\";\n\n\nexport function stopLoading() {\n  return {\n    type: \"STOP_LOADING\"\n  };\n}\nexport function initiateLoading() {\n  return {\n    type: \"INITIATE_LOADING\"\n  };\n}\nexport function reduxResetState() {\n  return { type: REDUX_RESET_STATE };\n}\n\n//----------------------------------------------------------------//\nexport function fetchProfileSuccess(data) {\n  return {\n    type: \"FETCH_PROFILE_SUCCESS\",\n    payload: {\n      data: data\n    }\n  };\n}\nexport function fetchProfile() {\n  let token = Auth.getAuthToken();\n\n  if (token === undefined) {\n    return { type: \"TOKEN_NOT_FOUND\" };\n  } else {\n    API.setAuthToken(token);\n  }\n  return dispatch => {\n    return axios\n      .get(API.url(\"userfetch\"))\n      .then(response => {\n        let json = response.data;\n        dispatch(fetchProfileSuccess(json));\n      })\n      .catch(error => {});\n  };\n}\nexport function authUpdateRegisterFormField(data) {\n  return { type: AUTH_UPDATE_REGISTER_FORM_FIELD, payload: data };\n}\nexport function authSubmitRegisterForm(data) {\n  return { type: AUTH_SUBMIT_REGISTER_FORM, payload: data };\n}\nexport function authInvalidateRegisterForm(data) {\n  return { type: AUTH_INVALIDATE_REGISTER_FORM, payload: data };\n}\nexport function authResetRegisterFormFields() {\n  return { type: AUTH_RESET_REGISTER_FORM_FIELDS };\n}\n\nexport function authServerRegisterUser(data) {\n  return dispatch => {\n    let nofity_message = message.info(\"Creating your account...\", 0);\n\n    return axios\n      .post(API.url(\"register\"), data)\n      .then(response => {\n        let json = response.data;\n        nofity_message();\n        dispatch(authSubmitRegisterForm(false));\n\n        if (json.success !== true) {\n          message.info(\"Error occoured while creating account.\", 3);\n          notification.warning({\n            message: \"Error Occoured\",\n            description: json.error\n          });\n        } else {\n          dispatch(authResetRegisterFormFields());\n          message.info(\"Account successfully created. You can login now.\", 3);\n          hashHistory.push('/auth/login');\n        }\n      })\n      .catch(error => {\n        dispatch(authSubmitRegisterForm(false));\n        notification.warning({ message: \"Error Occoured\", description: error });\n      });\n  };\n}\nexport function authUpdateLoginFormField(data) {\n  return { type: AUTH_UPDATE_LOGIN_FORM_FIELD, payload: data };\n}\nexport function authSubmitLoginForm(status) {\n  return { type: AUTH_SUBMIT_LOGIN_FORM, payload: status };\n}\nexport function authInvalidateLoginForm(data) {\n  return { type: AUTH_INVALIDATE_LOGIN_FORM, payload: data };\n}\n\nexport function authResetLoginFormFields() {\n  return { type: AUTH_RESET_LOGIN_FORM_FIELDS };\n}\n\nexport function authUpdateUserData(data) {\n  return { type: AUTH_UPDATE_USER_DATA, payload: data };\n}\n\nexport function authUpdateUserField(data) {\n  return { type: AUTH_UPDATE_USER_FIELD, payload: data };\n}\n\nexport function authResetUserData() {\n  return { type: AUTH_RESET_USER_DATA };\n}\n\nexport function authServerLoginUser(data) {\n  return dispatch => {\n    let nofity_message = message.info(\"Logging you in.. please wait\", 0);\n\n    return axios\n      .post(API.url(\"login\"), data)\n      .then(response => {\n        let json = response.data;\n        nofity_message();\n        dispatch(authSubmitLoginForm(false));\n\n        if (json.success === false) {\n          message.info( json.message || \"Please provide valid email & password\", 3);\n          notification.warning({\n            message: json.message || \"Error Occoured\",\n            description: JSON.stringify(json.error, null, 2)\n          });\n        } else {\n          dispatch(authResetLoginFormFields());\n          message.info(\"Successfully logged in\", 3);\n          Auth.setAccessToken(json.token);\n          API.setAuthToken(json.token);\n          const userToken = jwt.decode(json.token);\n          dispatch(authUpdateUserData(jwt.decode(json.token)));\n          if(userToken.type === '1'){\n            // hashHistory.push(routes.user_dashboard);\n          } else {\n           // hashHistory.push(routes.vendor_dashboard);\n          }\n          \n        }\n      })\n      .catch(error => {\n        nofity_message();\n        dispatch(authSubmitLoginForm(false));\n        if(error.response && error.response.data) {\n          notification.warning({\n            message: \"unable to login\",\n            description:\n            error.response.data.message\n          });\n        }\n      });\n  };\n}\n\nexport function authSubmitResetPasswordForm(status) {\n  return { type: AUTH_SUBMIT_RESET_PASSWORD_FORM, payload: status };\n}\nexport function authUpdateResetPasswordStatusField(data) {\n  return { type: AUTH_UPDATE_RESET_PASSWORD_STATUS_FIELD, payload: data };\n}\n\nexport function authInvalidateResetPasswordForm(data) {\n  return { type: AUTH_INVALIDATE_RESET_PASSWORD_FORM, payload: data };\n}\n\nexport function authServerResetPassword(data) {\n  return dispatch => {\n    return axios\n      .post(API.url(\"reset_password\"), data)\n      .then(response => {\n        let json = response.data;\n        dispatch(authSubmitResetPasswordForm(false));\n\n        if (json.success === false) {\n          message.info(\"User does not exist in System, Provide valid email\", 2);\n          notification.warning({\n            message: \"Error Occoured\",\n            description: json.description\n          });\n        } else {\n          message.info(\"Password reset request was successful.\", 3);\n          dispatch(\n            authUpdateResetPasswordStatusField({ field: \"done\", value: true })\n          );\n        }\n      })\n      .catch(error => {\n        dispatch(authSubmitResetPasswordForm(false));\n        if(error.response && error.response.data) {\n          notification.warning({\n            message: \"unable to reset password\",\n            description:\n            error.response.data.message\n          });\n        }\n      });\n  };\n}\n\nexport function userProfileLoaded(data) {\n  return { type: USER_PROFILE_LOADED, payload: data };\n}\n\nexport function userUpdateProfile(data) {\n  return { type: USER_UPDATE_PROFILE, payload: data };\n}\n\nexport function userUpdateProfileField(data) {\n  return { type: USER_UPDATE_PROFILE_FIELD, payload: data };\n}\n\nexport function userDeleteProfileField(data) {\n  return { type: USER_DELETE_PROFILE_FIELD, payload: data };\n}\n\nexport function updateField( data ) {\n\treturn {\n\t\ttype: UPDATE_FIELD,\n\t\tpayload: data\n\t}\n}\nexport function updateSection( data ) {\n\treturn {\n\t\ttype: UPDATE_SECTION,\n\t\tpayload: data\n\t}\n}\n\nexport function updateTabs( data ) {\n\treturn {\n\t\ttype: UPDATE_TABS,\n\t\tpayload: data\n\t}\n}\n\nexport function updateLoaded( data ) {\n\treturn {\n\t\ttype: UPDATE_LOADED,\n\t\tpayload: data\n\t}\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/actionTypes.js",
    "content": "export const HELLO_WORLD = 'HELLO_WORLD';\nexport const REDUX_RESET_STATE = 'REDUX_RESET_STATE';\n\n//ADMIN AUTH\nexport const ADMIN_GET_ALL_MENU = 'GET_ALL_MENU';\nexport const ADMIN_GET_ALL_MENU_SUCCESS = 'GET_ALL_MENU_SUCCESS';\nexport const ADMIN_UPDATE_NAVPATH = 'UPDATE_NAVPATH';\n// ADMIN LOGIN\nexport const ADMIN_FETCH_PROFILE_PENDING = 'FETCH_PROFILE_PENDING';\nexport const ADMIN_FETCH_PROFILE_SUCCESS = 'FETCH_PROFILE_SUCCESS';\nexport const ADMIN_LOGIN_PENDING = 'LOGIN_PENDING';\nexport const ADMIN_LOGIN_SUCCESS = 'LOGIN_SUCCESS';\nexport const ADMIN_LOGIN_ERROR = 'LOGIN_ERROR';\n\nexport const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';\n\n// auth constants\nexport const AUTH_UPDATE_REGISTER_FORM_FIELD = 'AUTH_UPDATE_REGISTER_FORM_FIELD';\nexport const AUTH_SUBMIT_REGISTER_FORM = 'AUTH_SUBMIT_REGISTER_FORM';\nexport const AUTH_INVALIDATE_REGISTER_FORM = 'AUTH_INVALIDATE_REGISTER_FORM';\nexport const AUTH_RESET_REGISTER_FORM_FIELDS = 'AUTH_RESET_REGISTER_FORM_FIELDS';\n\nexport const AUTH_UPDATE_USER_DATA = 'AUTH_UPDATE_USER_DATA';\nexport const AUTH_RESET_USER_DATA = 'AUTH_RESET_USER_DATA';\nexport const AUTH_UPDATE_USER_FIELD = 'AUTH_UPDATE_USER_FIELD';\n\nexport const AUTH_UPDATE_LOGIN_FORM_FIELD = 'AUTH_UPDATE_LOGIN_FORM_FIELD';\nexport const AUTH_SUBMIT_LOGIN_FORM = 'AUTH_SUBMIT_LOGIN_FORM';\nexport const AUTH_INVALIDATE_LOGIN_FORM = 'AUTH_INVALIDATE_LOGIN_FORM';\nexport const AUTH_RESET_LOGIN_FORM_FIELDS = 'AUTH_RESET_LOGIN_FORM_FIELDS';\n\nexport const AUTH_SUBMIT_RESET_PASSWORD_FORM = 'AUTH_SUBMIT_RESET_PASSWORD_FORM';\nexport const AUTH_UPDATE_RESET_PASSWORD_STATUS_FIELD = 'AUTH_UPDATE_RESET_PASSWORD_STATUS_FIELD';\nexport const AUTH_INVALIDATE_RESET_PASSWORD_FORM = 'AUTH_INVALIDATE_RESET_PASSWORD_FORM';\n\nexport const USER_PROFILE_LOADED = 'USER_PROFILE_LOADED';\nexport const USER_UPDATE_PROFILE = 'USER_UPDATE_PROFILE';\nexport const USER_UPDATE_PROFILE_FIELD = 'USER_UPDATE_PROFILE_FIELD';\nexport const USER_DELETE_PROFILE_FIELD = 'USER_DELETE_PROFILE_FIELD';\n\n// UI MODALS\nexport const UI_MODALS_UPDATE_FIELD = 'UI_MODALS_UPDATE_FIELD';\nexport const UI_PROCESSING_UPDATE_FIELD = 'UI_PROCESSING_UPDATE_FIELD';\nexport const UI_LOADED_UPDATE_FIELD = 'UI_LOADED_UPDATE_FIELD';\n\n// app constants\nexport const APP_CONFIG_TOGGLE_ASIDE = 'APP_CONFIG_TOGGLE_ASIDE';\nexport const INITIATE_LOADING = 'INITIATE_LOADING';\nexport const STOP_LOADING = 'STOP_LOADING';\n\nexport const COMMON_LOAD_VEHICLES = 'COMMON_LOAD_VEHICLES'\nexport const COMMON_LOAD_REVIEWS = 'COMMON_LOAD_REVIEWS'\nexport const COMMON_LOAD_VENDORS = 'COMMON_LOAD_VENDORS'\nexport const COMMON_SET_GEO= 'COMMON_SET_GEO'\nexport const COMMON_SET_GLOBAL_COUNT= 'COMMON_SET_GLOBAL_COUNT'\n\nexport const UPDATE_FIELD = 'UPDATE_FIELD';\nexport const UPDATE_SECTION = 'UPDATE_SECTION';\nexport const UPDATE_TABS = 'UPDATE_TABS';\nexport const UPDATE_LOADED = 'UPDATE_LOADED';\nexport const SET_MESSAGES = 'SET_MESSAGES';\nexport const UPDATE_MESSAGES = 'UPDATE_MESSAGES';\nexport const SET_USER_LANGUAGE = 'SET_USER_LANGUAGE';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/auth.scss",
    "content": ".errorMessage {\n   color: #b83636\n  }"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/auth/reducer.js",
    "content": "import {\n\tAUTH_UPDATE_REGISTER_FORM_FIELD,\n\tAUTH_SUBMIT_REGISTER_FORM,\n\tAUTH_INVALIDATE_REGISTER_FORM,\n\tAUTH_RESET_REGISTER_FORM_FIELDS,\n\tAUTH_UPDATE_USER_DATA,\n\tAUTH_RESET_USER_DATA,\n\tAUTH_UPDATE_USER_FIELD,\n\tAUTH_SUBMIT_LOGIN_FORM,\n\tAUTH_UPDATE_LOGIN_FORM_FIELD,\n\tAUTH_INVALIDATE_LOGIN_FORM,\n\tAUTH_RESET_LOGIN_FORM_FIELDS,\n\tAUTH_SUBMIT_RESET_PASSWORD_FORM,\n\tAUTH_UPDATE_RESET_PASSWORD_STATUS_FIELD,\n\tAUTH_INVALIDATE_RESET_PASSWORD_FORM,\n\n} from './actionTypes';\n\nimport Immutable from 'immutable';\n\nconst application_default_data = Immutable.Map({\n\n\tstatus: Immutable.Map({\n\t\tlogged_in: false,\n\t\tin_progress: false,\n    }),\n\n\tuser: Immutable.Map({}), // this contains the decoded token data\n\n\tregister: Immutable.Map({\n\t\tsubmit: false,\n\t\terror: false,\n\t\tname: '',\n\t\temail: '',\n\t\taddress: '',\n\t\tpassword: '',\n\t\tpassword_confirm: '',\n    }),\n\n\tlogin: Immutable.Map({\n\t\tsubmit: false,\n\t\terror: false,\n\t\temail: '',\n\t\tpassword: '',\n    }),\n\n\treset_password: Immutable.Map({\n\t\tsubmit: false,\n\t\tdone: false,\n\t\terror: false,\n    }),\n\n});\n\n\n\nfunction auth( auth = application_default_data, action ) {\n\n\n\n\tif ( action.type === AUTH_UPDATE_REGISTER_FORM_FIELD ) {\n\t\treturn auth.setIn(['register', action.payload.field ], action.payload.value );\n\t}\n\telse if ( action.type === AUTH_SUBMIT_REGISTER_FORM ) {\n\t\treturn auth.setIn(['register', 'submit'], action.payload );\n\t}\n\telse if ( action.type === AUTH_INVALIDATE_REGISTER_FORM ) {\n\t\treturn auth.setIn(['register', 'error'], action.payload );\n\t}\n\telse if ( action.type === AUTH_RESET_REGISTER_FORM_FIELDS ) {\n\t\treturn auth\n\t\t\t\t.setIn(['register', 'submit'], false )\n\t\t\t\t.setIn(['register', 'error'], false )\n\t\t\t\t.setIn(['register', 'name'], '' )\n\t\t\t\t.setIn(['register', 'email'], '' )\n\t\t\t\t.setIn(['register', 'address'], '' )\n\t\t\t\t.setIn(['register', 'password'], '' )\n\t\t\t\t.setIn(['register', 'password_confirm'], '' );\n\t}\n\n\telse if ( action.type === AUTH_SUBMIT_LOGIN_FORM ) {\n\t\treturn auth.setIn(['login', 'submit'], action.payload );\n\t}\n\n\telse if ( action.type === AUTH_UPDATE_LOGIN_FORM_FIELD ) {\n\t\treturn auth.setIn(['login', action.payload.field ], action.payload.value );\n\t}\n\n\telse if ( action.type === AUTH_INVALIDATE_LOGIN_FORM ) {\n\t\treturn auth.setIn(['login', 'error'], action.payload );\n\t}\n\telse if ( action.type === AUTH_RESET_LOGIN_FORM_FIELDS ) {\n\t\treturn auth\n\t\t\t\t.setIn(['login', 'submit'], false )\n\t\t\t\t.setIn(['login', 'error'], false )\n\t\t\t\t.setIn(['login', 'email'], '' )\n\t\t\t\t.setIn(['login', 'password'], '' );\n\t}\n\n\n\telse if ( action.type === AUTH_UPDATE_USER_DATA ) {\n\t\treturn auth.set('user', Immutable.Map(action.payload) );\n\t}\n\n\telse if ( action.type === AUTH_UPDATE_USER_FIELD ) {\n\t\treturn auth.setIn(['user', action.payload.key ], action.payload.value );\n\t}\n\n\telse if ( action.type === AUTH_RESET_USER_DATA ) {\n\t\treturn auth.set('user', Immutable.Map({}) );\n\t}\n\n\n\n\telse if ( action.type === AUTH_SUBMIT_RESET_PASSWORD_FORM ) {\n\t\treturn auth.setIn(['reset_password', 'submit'], action.payload );\n\t}\n\tif ( action.type === AUTH_UPDATE_RESET_PASSWORD_STATUS_FIELD ) {\n\t\treturn auth.setIn(['reset_password', action.payload.field ], action.payload.value );\n\t}\n\n\telse if ( action.type === AUTH_INVALIDATE_RESET_PASSWORD_FORM ) {\n\t\treturn auth.setIn(['reset_password', 'error'], action.payload );\n\t}\n\n\n\telse {\n\t\treturn auth;\n\t}\n\n\n}\n\n\nexport default auth;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/cart/actionTypes.js",
    "content": "export const LOAD_CART = 'LOAD_CART';\nexport const ADD_PRODUCT = 'ADD_PRODUCT';\nexport const REMOVE_PRODUCT = 'REMOVE_PRODUCT';\nexport const UPDATE_CART = 'UPDATE_CART';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/cart/actions.js",
    "content": "import { LOAD_CART, ADD_PRODUCT, REMOVE_PRODUCT } from './actionTypes';\n\nexport const loadCart = products => ({\n  type: LOAD_CART,\n  payload: products\n});\n\nexport const addProduct = product => ({\n  type: ADD_PRODUCT,\n  payload: product\n});\n\nexport const removeProduct = product => ({\n  type: REMOVE_PRODUCT,\n  payload: product\n});\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/cart/reducer.js",
    "content": "import { LOAD_CART, ADD_PRODUCT, REMOVE_PRODUCT } from './actionTypes';\n\nconst initialState = {\n  products: []\n};\n\nexport default function(state = initialState, action) {\n  switch (action.type) {\n    case LOAD_CART:\n      return {\n        ...state,\n        products: action.payload\n      };\n    case ADD_PRODUCT:\n      return {\n        ...state,\n        productToAdd: Object.assign({}, action.payload)\n      };\n    case REMOVE_PRODUCT:\n      return {\n        ...state,\n        productToRemove: Object.assign({}, action.payload)\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/filters/actionTypes.js",
    "content": "export const UPDATE_FILTER = 'UPDATE_FILTER';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/filters/actions.js",
    "content": "import { UPDATE_FILTER } from './actionTypes';\n\nexport const updateFilters = filters => ({\n  type: UPDATE_FILTER,\n  payload: filters\n});\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/filters/reducer.js",
    "content": "import { UPDATE_FILTER } from './actionTypes';\n\nconst initialState = {\n  item: []\n};\n\nexport default function(state = initialState, action) {\n  switch (action.type) {\n    case UPDATE_FILTER:\n      return {\n        ...state,\n        items: action.payload\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/reducers.js",
    "content": "import { combineReducers } from 'redux';\nimport shelfReducer from './shelf/reducer';\nimport cartReducer from './cart/reducer';\nimport totalReducer from './total/reducer';\nimport filtersReducer from './filters/reducer';\nimport sortReducer from './sort/reducer';\nimport authReducer from './auth/reducer';\n\n\nexport default combineReducers({\n  shelf: shelfReducer,\n  cart: cartReducer,\n  total: totalReducer,\n  filters: filtersReducer,\n  sort: sortReducer,\n  auth:authReducer\n});\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/shelf/actionTypes.js",
    "content": "export const FETCH_PRODUCTS = 'FETCH_PRODUCTS';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/shelf/actions.js",
    "content": "import { FETCH_PRODUCTS } from './actionTypes';\nimport axios from 'axios';\n\nimport { productsAPI } from '../util';\n\nconst compare = {\n  lowestprice: (a, b) => {\n    if (a.price < b.price) return -1;\n    if (a.price > b.price) return 1;\n    return 0;\n  },\n  highestprice: (a, b) => {\n    if (a.price > b.price) return -1;\n    if (a.price < b.price) return 1;\n    return 0;\n  }\n};\n\nexport const fetchProducts = (filters, sortBy, callback) => dispatch => {\n  return axios\n    .get(productsAPI)\n    .then(res => {\n      let { products } = res.data;\n\n      if (!!filters && filters.length > 0) {\n        products = products.filter(p =>\n          filters.find(f => p.availableSizes.find(size => size === f))\n        );\n      }\n\n      if (!!sortBy) {\n        products = products.sort(compare[sortBy]);\n      }\n\n      if (!!callback) {\n        callback();\n      }\n\n      return dispatch({\n        type: FETCH_PRODUCTS,\n        payload: products\n      });\n    })\n    .catch(err => {\n      console.log('Could not fetch products. Try again later.');\n    });\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/shelf/reducer.js",
    "content": "import { FETCH_PRODUCTS } from './actionTypes';\n\nconst initialState = {\n  products: []\n};\n\nexport default function(state = initialState, action) {\n  switch (action.type) {\n    case FETCH_PRODUCTS:\n      return {\n        ...state,\n        products: action.payload\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/sort/actionTypes.js",
    "content": "export const UPDATE_SORT = 'UPDATE_SORT';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/sort/actions.js",
    "content": "import { UPDATE_SORT } from './actionTypes';\n\nexport const updateSort = sort => ({\n  type: UPDATE_SORT,\n  payload: sort\n});\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/sort/reducer.js",
    "content": "import { UPDATE_SORT } from './actionTypes';\n\nconst initialState = {\n  type: ''\n};\n\nexport default function(state = initialState, action) {\n  switch (action.type) {\n    case UPDATE_SORT:\n      return {\n        ...state,\n        type: action.payload\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/store.js",
    "content": "import { compose, createStore, applyMiddleware } from 'redux';\nimport thunk from 'redux-thunk';\nimport rootReducer from './reducers';\n\nexport default initialState => {\n  initialState =\n    JSON.parse(window.localStorage.getItem('state')) || initialState;\n\n  const store = createStore(\n    rootReducer,\n    initialState,\n    compose( applyMiddleware(thunk), window.devToolsExtension ? window.devToolsExtension() : f => f )\n  );\n\n  store.subscribe(() => {\n    const state = store.getState();\n    const persist = {\n      cart: state.cart,\n      total: state.total\n    };\n\n    window.localStorage.setItem('state', JSON.stringify(persist));\n  });\n\n  return store;\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/total/actionTypes.js",
    "content": "export const UPDATE_CART = 'UPDATE_CART';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/total/actions.js",
    "content": "import { UPDATE_CART } from './actionTypes';\n\nexport const updateCart = cartProducts => dispatch => {\n  let productQuantity = cartProducts.reduce((sum, p) => {\n    sum += p.quantity;\n    return sum;\n  }, 0);\n\n  let totalPrice = cartProducts.reduce((sum, p) => {\n    sum += p.price * p.quantity;\n    return sum;\n  }, 0);\n\n  let installments = cartProducts.reduce((greater, p) => {\n    greater = p.installments > greater ? p.installments : greater;\n    return greater;\n  }, 0);\n\n  let cartTotal = {\n    productQuantity,\n    installments,\n    totalPrice,\n    currencyId: 'USD',\n    currencyFormat: '$'\n  };\n\n  dispatch({\n    type: UPDATE_CART,\n    payload: cartTotal\n  });\n};\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/total/reducer.js",
    "content": "import { UPDATE_CART } from './actionTypes';\n\nconst initialState = {\n  data: {\n    productQuantity: 0,\n    installments: 0,\n    totalPrice: 0,\n    currencyId: 'USD',\n    currencyFormat: '$'\n  }\n};\n\nexport default function(state = initialState, action) {\n  switch (action.type) {\n    case UPDATE_CART:\n      return {\n        ...state,\n        data: action.payload\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/services/util.js",
    "content": "export const formatPrice = (x, currency) => {\n  switch (currency) {\n    case 'BRL':\n      return x.toFixed(2).replace('.', ',');\n    default:\n      return x.toFixed(2);\n  }\n};\n\nexport const productsAPI =\n  'http://ms-commerce.com/cart/v1/products';\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/setupTests.js",
    "content": "import React from 'react';\nimport Enzyme, { shallow, render, mount } from 'enzyme';\nimport adapter from 'enzyme-adapter-react-16';\n\nEnzyme.configure({ adapter: new adapter() });\n\n/* Globals only for tests */\nglobal.React = React;\nglobal.shallow = shallow;\nglobal.render = render;\nglobal.mount = mount;\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/util/helper/index.js",
    "content": "\nexport  default class Util{\n  static validateEmail(email){\n     var 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,}))$/;\n   return re.test(email);\n  }\n  static getFileName( url ) {\n   return url ? url.split('/').pop() : null;\n }\n static uid() {\n   return Math.random().toString(34).slice(2);\n }\n}"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/util/middleware/auth.js",
    "content": "import * as API from '../../api'\n\nexport default {\n\n\tloggedIn: () => {\n\t\treturn !! localStorage.token\n\t},\n\n\tsetAccessToken: (token) => {\n\t\tlocalStorage.token = token;\n\t},\n\n\tgetAccessToken: (token) => {\n\t\treturn localStorage.token;\n\t},\n\n\n\tdeleteAccessToken: () => {\n\t\tdelete localStorage.token\n\t},\n\n\tlogout: () => {\n\t\tdelete localStorage.token;\n\t\tdelete localStorage.user_hasPassword;\n\t\tdelete localStorage.user_userType;\n\t\tdelete localStorage.auth_background;\n\t\tdelete sessionStorage.redirect_after_login;\n\t\tAPI.setAuthToken();\n\t},\n}\n\n"
  },
  {
    "path": "dockerized-containers/e-Commerce-Client/src/util/middleware/index.js",
    "content": "import Auth from './auth';\n\n\nfunction authenticatedUsersOnly( nextState, replace ) {\n\tif( nextState.location.pathname !== '/user/dashboard' ) {\n\t\tif ( sessionStorage.redirect_after_login ) {\n\t\t\tlocalStorage.removeItem('redirect_after_login');\n\t\t}\n\t\tsessionStorage.setItem( 'redirect_after_login', nextState.location.pathname);\n\t}\n\n\tif ( !Auth.loggedIn() ) {\n\t\treplace({\n\t\t\tpathname: '/auth/login',\n\t\t\tstate: { nextPathname: nextState.location.pathname }\n\t\t});\n\t}\n}\n\n\n\nfunction userTypeHostOnly( nextState, replace, store ) {\n\tconst state = store.getState();\n\n\tif ( state.auth.get('user').get('userType') !== 2 ) {\n\t\treplace({\n\t\t\tpathname: '/user/dashboard/home',\n\t\t\tstate: { nextPathname: nextState.location.pathname }\n\t\t});\n\t}\n\n}\nfunction notLoggedIn( nextState, replace ) {\n\tif ( Auth.loggedIn() ) {\n\t\treplace({\n\t\t\tpathname: '/user/dashboard/home',\n\t\t\tstate: { nextPathname: nextState.location.pathname }\n\t\t});\n\t}\n}\n\nfunction logoutUser( nextState, replace ) {\n\tAuth.logout();\n\treplace({\n\t\tpathname: '/user/dashboard/home',\n\t\tstate: { nextPathname: nextState.location.pathname }\n\t});\n\n}\n\n\nexport { authenticatedUsersOnly };\nexport { notLoggedIn };\nexport { logoutUser };\nexport { userTypeHostOnly };\n"
  },
  {
    "path": "dockerized-containers/proxy/default.conf",
    "content": "ssl_certificate /etc/nginx/ssl/pac.crt;\nssl_certificate_key /etc/nginx/ssl/pac.key;\n\nserver {\n    server_name  ms-commerce.com;\n    listen              80;\n    listen              443 ssl;\n    location / {\n        proxy_pass         http://ms_commerce_client:3003;\n        proxy_http_version 1.1;\n        proxy_set_header   Upgrade $http_upgrade;\n        proxy_set_header   Connection \"upgrade\";\n    }\n    location /api/ {\n        proxy_pass         http://ms_commerce_auth:3001/api/;\n        proxy_redirect     off;\n        proxy_set_header   Host $host;\n        proxy_set_header   X-Real-IP $remote_addr;\n        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header   X-Forwarded-Host $server_name;\n        proxy_http_version 1.1;\n        proxy_set_header   Upgrade $http_upgrade;\n        proxy_set_header   Connection \"upgrade\";\n    }\n     location /admin/ {\n        proxy_pass         http://ms_commerce_admin:3002/api/;\n        proxy_redirect     off;\n        proxy_set_header   Host $host;\n        proxy_set_header   X-Real-IP $remote_addr;\n        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header   X-Forwarded-Host $server_name;\n        proxy_http_version 1.1;\n        proxy_set_header   Upgrade $http_upgrade;\n        proxy_set_header   Connection \"upgrade\";\n    }\n     location /cart/ {\n        proxy_pass         http://ms_commerce_cart:3004/api/;\n        proxy_redirect     off;\n        proxy_set_header   Host $host;\n        proxy_set_header   X-Real-IP $remote_addr;\n        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header   X-Forwarded-Host $server_name;\n        proxy_http_version 1.1;\n        proxy_set_header   Upgrade $http_upgrade;\n        proxy_set_header   Connection \"upgrade\";\n    }\n}"
  },
  {
    "path": "dockerized-containers/proxy/hosts",
    "content": "#\n# localhost is used to configure the loopback interface\n# when the system is booting.  Do not change this entry.\n#\n127.0.0.1       localhost ms-commerce.com\n255.255.255.255 broadcasthost\n::1             localhost\n"
  },
  {
    "path": "dockerized-containers/proxy/ssl/pac.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIICuzCCAiQCCQC+/UzcIDAe1jANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBhMC\nSU4xDDAKBgNVBAgMA0dvYTERMA8GA1UEBwwIUG9ydm9yaW0xJDAiBgNVBAoMG1Ny\naWphbiBUZWNobm9sb2dpZXMgUHZ0IEx0ZDEMMAoGA1UECwwDR29hMRgwFgYDVQQD\nDA9kaXZlcnNleWlvdC5jb20xIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAZGl2ZXJz\nZXkuY29tMB4XDTE5MDEyMDAwMjEwOVoXDTI5MDExNzAwMjEwOVowgaExCzAJBgNV\nBAYTAklOMQwwCgYDVQQIDANHb2ExETAPBgNVBAcMCFBvcnZvcmltMSQwIgYDVQQK\nDBtTcmlqYW4gVGVjaG5vbG9naWVzIFB2dCBMdGQxDDAKBgNVBAsMA0dvYTEYMBYG\nA1UEAwwPZGl2ZXJzZXlpb3QuY29tMSMwIQYJKoZIhvcNAQkBFhRzdXBwb3J0QGRp\ndmVyc2V5LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1QfJ81Q9Drzp\nEujr3pz5S0kvXrXREVNPeKTf+fN8iJr6bMlmaDd0KvVXKt1nRIJxOUHQ1AQuKNlR\n1Ly5M8bLk6u1MIYZNzLl1x06UX501NtgVX2ig5wZbdOONeUreI5Ss5VsAJZHgFR8\nxNRecBeG+loQUmj9bAI6d5ilY/bhvV0CAwEAATANBgkqhkiG9w0BAQsFAAOBgQDV\nBhPhasAnTDoJdqRTkLIKHQngzYf91j7Wy8cm7WOtIpSH3BuzZEzrhgGmInJT0QWa\nbTMSemvkxnuKZnJloGC4BdE0z3ec/ubSrN4AmefoaDbENJrahPLULYkkaRasmdDo\nS4Mm2oN1mpNCE2VW8eudRIHlQbeaBjkgnHOhp6gBeg==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "dockerized-containers/proxy/ssl/pac.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANUHyfNUPQ686RLo\n696c+UtJL1610RFTT3ik3/nzfIia+mzJZmg3dCr1VyrdZ0SCcTlB0NQELijZUdS8\nuTPGy5OrtTCGGTcy5dcdOlF+dNTbYFV9ooOcGW3TjjXlK3iOUrOVbACWR4BUfMTU\nXnAXhvpaEFJo/WwCOneYpWP24b1dAgMBAAECgYA2ya0HtreJTc6HvX3EIA0Bbs4P\nBqXBVfLPbV/pMdTqcSlMxzNeRDzNO5HyhUSk2wNxnVqu3HBesx2Xn/3lsg/y71rt\nPIM2vd8ccOZL39hZCwEnixvhwr1VktGXUBtdi7ipMkYDLl9SUFMNKFexHSQ96Xl6\nbfcdhwK/dZxOVOGJRQJBAPci1ij7gEL8xsA8xxCzqDDPruFCI5+SUcco88vWkXZ5\nZYJZVNOk0SAAdYw9dUjKjwQKBDQ+SbMyhx2nT5QDTicCQQDcq8y5ulkxdzUHHoxq\nj8iZlNmErRfofiyOTJcc4/9kqyIyQGGLSAuCmAVqKxKzjwFXN/UuJYbLBlKAMMOc\nkk7bAkAYZOrozrKBajwgG5+2qVUvxEBJ4eJsTOAfnY47D6n6HM+FR1YVMg6mbwUr\nW6GpFr15M5fopEFYG+O0bKBxRsY/AkACwRozD0Jhva0pw5XZFqZYVGVKpKZxvnFr\n7UTNlYLwjLpGikstY97Q6HjY1GTNXPGVVxt2Uf2WtyN8eh9W6vSVAkEAxtiPp8w5\nsXiWHKKq9VkYpYgUF4WkhUCxx4crWpaIQgXJwtQ6bKJeBN8r+JklYsPtveNYZYbl\nbn8bkcfdRwxcog==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-commit",
    "content": "#!/bin/sh\n\necho \"Running Pre-Commit hook\"\n\n# This script should be saved in a git repo as a hook file, e.g. .git/hooks/pre-receive.\n# It looks for scripts in the .git/hooks/pre-receive.d directory and executes them in order,\n# passing along stdin. If any script exits with a non-zero status, this script exits.\n\nscript_dir=$(dirname $0)\nhook_name=$(basename $0)\n\nhook_dir=\"$script_dir/$hook_name.d\"\n\nif [[ -d $hook_dir ]]; then\n  stdin=$(cat /dev/stdin)\n\n  for hook in $hook_dir/*; do\n    echo \"Running $hook_name/$hook hook\"\n    echo \"$stdin\" | $hook \"$@\"\n\n    exit_code=$?\n\n    if [ $exit_code != 0 ]; then\n      exit $exit_code\n    fi\n  done\nfi\n\nexit 0\n\n"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-commit.d/articles-management-service",
    "content": "#!/bin/sh\n\ncd ./services/articles-management\nnpm run lint"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-commit.d/events-management-service",
    "content": "#!/bin/sh\n\ncd ./services/events-management\nnpm run lint"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-commit.d/notification-service",
    "content": "#!/bin/sh\n\ncd ./services/notification\nnpm run lint"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-commit.d/user-management-service",
    "content": "#!/bin/sh\n\ncd ./services/user-management\nnpm run lint"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-push",
    "content": "#!/bin/sh\n\necho \"Running Pre-Push hook\"\n\n# This script should be saved in a git repo as a hook file, e.g. .git/hooks/pre-receive.\n# It looks for scripts in the .git/hooks/pre-receive.d directory and executes them in order,\n# passing along stdin. If any script exits with a non-zero status, this script exits.\n\nscript_dir=$(dirname $0)\nhook_name=$(basename $0)\n\nhook_dir=\"$script_dir/$hook_name.d\"\n\nif [[ -d $hook_dir ]]; then\n  stdin=$(cat /dev/stdin)\n\n  for hook in $hook_dir/*; do\n    echo \"Running $hook_name/$hook hook\"\n    echo \"$stdin\" | $hook \"$@\"\n\n    exit_code=$?\n\n    if [ $exit_code != 0 ]; then\n      exit $exit_code\n    fi\n  done\nfi\n\nexit 0"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-push.d/articles-management-service",
    "content": "#!/bin/sh\n\ncd ./services/articles-management\nnpm run testOnly"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-push.d/events-management-service",
    "content": "#!/bin/sh\n\ncd ./services/events-management\nnpm run testOnly"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-push.d/notification-service",
    "content": "#!/bin/sh\n\ncd ./services/notification\nnpm run testOnly"
  },
  {
    "path": "event-driven-microservices-docker/.githooks/pre-push.d/user-management-service",
    "content": "#!/bin/sh\n\ncd ./services/user-management\nnpm run testOnly"
  },
  {
    "path": "event-driven-microservices-docker/.gitignore",
    "content": "\nnode/node_modules\n.DS_Store\n\nnode/npm-debug.log\n.DS_Store\n"
  },
  {
    "path": "event-driven-microservices-docker/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  articles-management:\n    container_name: articles-management\n    build:\n      context: ./services/articles-management\n      dockerfile: Dockerfile\n    depends_on:\n      - mongo  \n    ports:\n      - \"3000:3000\"\n    environment:\n      - PORT=3000\n      - MESSAGE_BUS=amqp://rabbitmq\n      - DB_URI=mongodb://mongo/test\n    links:\n      - rabbitmq\n  mongo:\n    image: mongo\n    container_name: mongo\n    restart: unless-stopped \n    volumes:\n      - mongo_data:/data/configdb\n    ports:\n      - 27017:27017\n  events-management:\n    container_name: events-management\n    build:\n      context: ./services/events-management\n      dockerfile: Dockerfile\n    depends_on:\n      - mongo    \n    ports:\n      - \"3001:3000\"\n    environment:\n      - PORT=3000\n      - MESSAGE_BUS=amqp://rabbitmq\n      - DB_URI=mongodb://mongo/test\n\n    links:\n      - rabbitmq\n  user-management:\n    container_name: user-management\n    depends_on:\n      - mongo  \n    build:\n      context: ./services/user-management\n      dockerfile: Dockerfile\n    ports:\n      - \"3002:3000\"\n    environment:\n      - PORT=3000\n      - MESSAGE_BUS=amqp://rabbitmq\n      - DB_URI=mongodb://mongo/test\n\n    links:\n      - rabbitmq\n  authentication:\n    container_name: authentication\n    build:\n      context: ./services/authentication\n      dockerfile: Dockerfile\n    ports:\n      - \"3003:3000\"\n    environment:\n      - PORT=3000\n      - MESSAGE_BUS=amqp://rabbitmq\n      - DB_URI=mongodb://mongo/test\n    links:\n      - rabbitmq\n  notification:\n    container_name: notification\n    build:\n      context: ./services/notification\n      dockerfile: Dockerfile\n    environment:\n      - MESSAGE_BUS=amqp://rabbitmq\n      - EMAIL_SERVICE=gmail\n      - EMAIL_ID=noreply.localnewsapplication@gmail.com\n      - EMAIL_PASSWORD=Testing0*\n      - ADMIN_EMAIL=localnewsapp340ct@gmail.com\n      - DB_URI=mongodb://mongo/test\n    links:\n      - rabbitmq\n  rabbitmq:\n    container_name: rabbitmq\n    image: rabbitmq:3-management\n    ports:\n      - \"5672:5672\"\n      - \"15672:15672\"\n    volumes:\n      - rabbitmq_data:/data\n\nvolumes:\n  mongo_data:\n    name: global_mongo\n  rabbitmq_data:\n    name: global_mq"
  },
  {
    "path": "event-driven-microservices-docker/run_all_tests",
    "content": "#!/bin/sh\n\ncd ./services/articles-management\nnpm test\ncd -\n\ncd ./services/events-management\nnpm test\ncd -\n\ncd ./services/user-management\nnpm test\ncd - \n\ncd ./services/notification\nnpm test\ncd -"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/.dockerignore",
    "content": "node_modules\npackage-lock.json\n.env"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/.eslintignore",
    "content": "node_modules\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/.eslintrc.yml",
    "content": "extends: airbnb-base\nenv:\n  jest: true\n\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/.gitignore",
    "content": "node_modules\npackage-lock.json\n.env\ncoverage"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/Dockerfile",
    "content": "# Use Node v11.2 as the base image.\nFROM node:11.2.0-alpine\n\n#Set the working directory\nWORKDIR /usr/app\n\n# Copy everything in current directory to /server folder\nADD . /server\n\n# Install dependencies\nRUN cd /server; \\\n    npm install\n\nEXPOSE 3000\n\n# Run node \nCMD [\"node\", \"/server/src/server.js\"]"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/package.json",
    "content": "{\n  \"name\": \"articles-management\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Articles Management Service - responsible for handling news articles related operations such as creating, reading, updating, deleting, verifying, reporting etc.\",\n  \"main\": \"./src/server.js\",\n  \"scripts\": {\n    \"start\": \"node ./src/server.js\",\n    \"test\": \"jest --coverage\",\n    \"watch\": \"jest --coverage --watchAll\",\n    \"lint\": \"eslint ./src && eslint ./tests\",\n    \"testOnly\": \"jest\"\n  },\n  \"jest\": {\n    \"testEnvironment\": \"node\",\n    \"verbose\": true,\n    \"coverageThreshold\": {\n      \"global\": {\n        \"branches\": 100,\n        \"functions\": 100,\n        \"lines\": 100,\n        \"statements\": -10\n      }\n    }\n  },\n  \"author\": \"Rithin Chalumuri\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"amqp-ts-async\": \"^1.3.7\",\n    \"dotenv\": \"^6.1.0\",\n    \"koa\": \"^2.6.2\",\n    \"koa-bodyparser\": \"^4.2.1\",\n    \"koa-helmet\": \"^4.0.0\",\n    \"koa-jwt\": \"^3.5.1\",\n    \"koa-logger\": \"^3.2.0\",\n    \"koa-router\": \"^7.4.0\",\n    \"mongoose\": \"^5.3.13\",\n    \"winston\": \"^3.1.0\"\n  },\n  \"devDependencies\": {\n    \"eslint\": \"^5.9.0\",\n    \"eslint-config-airbnb-base\": \"^13.1.0\",\n    \"eslint-plugin-import\": \"^2.14.0\",\n    \"jest\": \"^23.6.0\",\n    \"supertest\": \"^3.3.0\"\n  }\n}\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/app.js",
    "content": "// Import the required npm packages\nconst Koa = require('koa');\nconst Logger = require('koa-logger');\nconst Helmet = require('koa-helmet');\nconst BodyParser = require('koa-bodyparser');\n\n// Get the API routes  file\nconst articleRouter = require('./routes/article.routes');\n\n// Init Koa API App\nconst app = new Koa();\napp.use(Logger());\napp.use(BodyParser());\napp.use(Helmet());\n\n// Setup the API routes\napp.use(articleRouter.routes()).use(articleRouter.allowedMethods({ throw: true }));\n\nmodule.exports = app;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/controllers/__mocks__/article.controller.js",
    "content": "const articleController = {};\n\narticleController.find = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = '';\n});\n\narticleController.findById = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\narticleController.add = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = '';\n});\n\narticleController.update = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\narticleController.delete = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\nmodule.exports = articleController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/controllers/article.controller.js",
    "content": "const Article = require('../models/article.model');\nconst articleAddedMessage = require('../message-bus/send/article.added');\n\nconst articleController = {\n  find: async (ctx) => {\n    ctx.body = await Article.find();\n  },\n\n  findById: async (ctx) => {\n    try {\n      const result = await Article.findById(ctx.params.id);\n      if (!result) {\n        ctx.throw(404, 'Article Not Found');\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n\n  add: async (ctx) => {\n    try {\n      const newArticle = await Article.create(ctx.request.body);\n      ctx.body = newArticle;\n      articleAddedMessage.send(newArticle);\n    } catch (err) {\n      ctx.throw(422);\n    }\n  },\n\n  update: async (ctx) => {\n    try {\n      const result = await Article.findByIdAndUpdate(\n        ctx.params.id,\n        ctx.request.body,\n      );\n      if (!result) {\n        ctx.throw(404);\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n\n  delete: async (ctx) => {\n    try {\n      const result = await Article.findByIdAndRemove(ctx.params.id);\n      if (!result) {\n        ctx.throw(404);\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n};\n\nmodule.exports = articleController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/environment/config.js",
    "content": "const config = {\n  name: 'Article Management Service',\n  baseAPIRoute: 'api',\n  port: process.env.PORT || 8080,\n  messagebus: process.env.MESSAGE_BUS || 'amqp://rabbitmq',\n  environment: process.env.ENVIRONMENT || 'dev',\n  db: {\n    uri: process.env.DB_URI,\n    username: process.env.DB_USERNAME ,\n    password: process.env.DB_PASSWORD ,\n  },\n  services: {\n  },\n  messageTimeout: 500,\n  jwtsecret: 'yoursecretkey',\n};\n\nconfig.startedMessage = `${config.name} is running on port ${config.port}/`;\n\nmodule.exports = config;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/message-bus/send/__mocks__/article.added.js",
    "content": "/* eslint-disable no-unused-vars */\nconst addedEventMessage = {};\n\naddedEventMessage.send = (article) => {\n};\n\nmodule.exports = addedEventMessage;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/message-bus/send/article.added.js",
    "content": "const logger = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../../environment/config');\n\nconst exchangeName = 'articles.added';\n\nmodule.exports = {\n  send: (article) => {\n    try {\n      if (!article) {\n        throw new Error('Sould send a valid article to message queue');\n      }\n      const connection = new amqp.Connection(config.messagebus);\n      const exchange = connection.declareExchange(exchangeName, 'fanout', { durable: false });\n      const message = new amqp.Message(JSON.stringify(article));\n      exchange.send(message);\n      setTimeout(() => {\n        connection.close();\n      }, config.messageTimeout);\n    } catch (err) {\n      logger.error(`Error Sending Article Added Event to ${exchangeName}: ${err}`);\n    }\n  },\n};\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/middlewares/__mocks__/jwt.js",
    "content": "const jwt = jest.fn((ctx, next) => {\n  next();\n});\n\nmodule.exports = jwt;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/middlewares/jwt.js",
    "content": "const koaJwt = require('koa-jwt');\nconst config = require('../environment/config');\n\nmodule.exports = koaJwt({\n  secret: config.jwtsecret,\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/models/__mocks__/article.model.js",
    "content": "/* eslint-disable arrow-body-style */\n\nconst articleModel = {};\n\nlet data = [];\n\narticleModel.find = jest.fn(() => data);\n\narticleModel.findById = jest.fn((id) => {\n  return data.find(article => article.id === id);\n});\n\narticleModel.create = jest.fn((article) => {\n  data.push(article);\n  return article;\n});\n\narticleModel.findByIdAndUpdate = jest.fn((id, updatedArticle) => {\n  const index = data.findIndex(article => article.id === id);\n  if (index >= 0) {\n    data[index] = updatedArticle;\n  }\n  return updatedArticle;\n});\n\narticleModel.findByIdAndRemove = jest.fn((id) => {\n  const index = data.findIndex(article => article.id === id);\n  data.splice(index, 1);\n  return id;\n});\n\narticleModel.count = () => data.length;\narticleModel.reset = () => { data = []; };\n\nmodule.exports = articleModel;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/models/article.model.js",
    "content": "const mongoose = require('mongoose');\n\nconst ArticleSchema = new mongoose.Schema({\n  authorUID: { type: String, require: true },\n  createdDate: { type: Date, default: Date.now },\n  updatedDate: { type: Date, default: Date.now },\n  title: { type: String, require: true },\n  description: { type: String, require: true },\n  body: { type: String, require: true },\n  meta: {\n    likes: { type: Number, default: 0 },\n  },\n  status: { type: Number },\n  imagesUID: [String],\n  tags: [String],\n});\n\nmodule.exports = mongoose.model('Article', ArticleSchema);\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/routes/article.routes.js",
    "content": "const KoaRouter = require('koa-router');\nconst config = require('../environment/config');\nconst articleController = require('../controllers/article.controller');\nconst jwt = require('../middlewares/jwt');\n\nconst api = 'articles';\n\nconst router = new KoaRouter();\n\nrouter.prefix(`/${config.baseAPIRoute}/${api}`);\n\n// GET /api/articles\nrouter.get('/', articleController.find);\n\n// POST /api/articles\nrouter.post('/', articleController.add);\n\n// GET /api/articles/id\nrouter.get('/:id', articleController.findById);\n\n// PUT /api/articles/id\nrouter.put('/:id', articleController.update);\n\n// DELETE /api/articles/id\nrouter.delete('/:id', articleController.delete);\n\nmodule.exports = router;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/src/server.js",
    "content": "/* eslint-disable no-console */\n\n// Init the environment variables and server configurations\nrequire('dotenv').config();\n\n// Import the required packages\nconst Mongoose = require('mongoose');\nconst config = require('./environment/config');\nconst app = require('./app');\n\n// Init Database Connection\nMongoose.connect('mongodb://mongo/test');\nMongoose.connection.on('error', console.error);\n\n// Run the API Server\napp.listen(config.port, () => {\n  console.log(config.startedMessage);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/__snapshots__/article.added.message.send.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Send Should correcly parse the json object 1`] = `mockConstructor {}`;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/app.test.js",
    "content": "/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\n\nconst Koa = require('koa');\nconst articleRouter = require('../../src/routes/article.routes');\n\nconst mockArticleRoutes = jest.fn(() => { return async (ctx, next) => {}; });\narticleRouter.routes = mockArticleRoutes;\n\ndescribe('Koa App', () => {\n  test('Should return valid koa application', () => {\n    const app = require('../../src/app');\n    expect(app).toBeInstanceOf(Koa);\n  });\n\n  test('Should have article routes', () => {\n    require('../../src/app');\n    expect(mockArticleRoutes.mock.calls.length).toBe(1);\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/article.added.message.send.test.js",
    "content": "/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\njest.mock('winston');\njest.mock('amqp-ts-async');\njest.useFakeTimers();\n\nconst winston = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../../src/environment/config');\n\nconst message = {\n  title: 'Test Article',\n  description: 'Test Text',\n};\n\ndescribe('Message Broker Connection', () => {\n  afterEach(() => {\n    amqp.close.mockClear();\n    amqp.declareExchange.mockClear();\n    jest.mock('amqp-ts-async');\n  });\n\n  test('Should connect to correct url', () => {\n    require('../../src/message-bus/send/article.added').send(message);\n    expect(amqp.Connection).toBeCalledTimes(1);\n    expect(amqp.Connection).toBeCalledWith(config.messagebus);\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should init with correct exchange details', () => {\n    require('../../src/message-bus/send/article.added').send(message);\n    expect(amqp.declareExchange.mock.calls.length).toBe(1);\n    expect(amqp.declareExchange.mock.calls[0][0]).toBe('articles.added');\n    expect(amqp.declareExchange.mock.calls[0][1]).toBe('fanout');\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should close connection after timeout', () => {\n    jest.runAllTimers();\n    require('../../src/message-bus/send/article.added').send(message);\n    expect(amqp.close.mock.calls.length).toBeGreaterThan(0);\n    expect(winston.error).not.toBeCalled();\n  });\n});\n\ndescribe('Send', () => {\n  afterEach(() => {\n    amqp.send.mockClear();\n    jest.mock('amqp-ts-async');\n  });\n\n  test('Should send succesfully when valid article is passed', () => {\n    require('../../src/message-bus/send/article.added').send(message);\n    expect(amqp.send).toHaveBeenCalled();\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should correcly parse the json object', () => {\n    require('../../src/message-bus/send/article.added').send(message);\n    expect(amqp.send).toBeCalledTimes(1);\n    expect(amqp.Message).toBeCalledWith(JSON.stringify(message));\n    expect(amqp.send.mock.calls[0][0]).toMatchSnapshot();\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should log exception if there null article is passed', () => {\n    require('../../src/message-bus/send/article.added').send(null);\n    expect(amqp.send).not.toBeCalled();\n    expect(winston.error).toBeCalled();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/article.controller.test.js",
    "content": "// #region Disabled ESLint Rules...\n\n/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n\n// #endregion\n\n// #region Setup Mocks...\n\njest.mock('../../src/models/article.model');\njest.mock('../../src/message-bus/send/article.added');\n\n// #endregion\n\n// #region Imports...\n\nconst articleModel = require('../../src/models/article.model');\nconst articleController = require('../../src/controllers/article.controller');\n\n// #endregion\n\n// #region Methods...\nconst sampleArticle = {\n  id: 123,\n  title: 'Test Article',\n};\n\nconst createMockContext = (context = {}) => {\n  const ctx = context;\n  ctx.throw = jest.fn((errorCode) => {});\n  return ctx;\n};\n\n// #endregion\n\n// #region Unit Tests...\n\n// #region ArticleController_add\n\ndescribe('add', async () => {\n  const createMockOriginalImplementation = articleModel.create;\n\n  beforeEach(() => {\n    articleModel.create.mockClear();\n  });\n\n  afterEach(() => {\n    articleModel.reset();\n    articleModel.create = createMockOriginalImplementation;\n  });\n\n  test('should add article when valid data is passed', async () => {\n    const ctx = createMockContext({ request: { body: sampleArticle } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(sampleArticle);\n    expect(ctx.body).toMatchObject(sampleArticle);\n    expect(ctx.throw).not.toBeCalled();\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should add article successfully with multiple tags', async () => {\n    const newSampleArticle = Object.assign({}, sampleArticle);\n    newSampleArticle.tags = ['Sample', 'Article'];\n\n    const ctx = createMockContext({ request: { body: newSampleArticle } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(newSampleArticle);\n    expect(ctx.body).toMatchObject(newSampleArticle);\n    expect(ctx.throw).not.toBeCalled();\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should add article successfully without images', async () => {\n    const ctx = createMockContext({ request: { body: sampleArticle } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(sampleArticle);\n    expect(ctx.body).toMatchObject(sampleArticle);\n    expect(ctx.throw).not.toBeCalled();\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should add article successfully with images', async () => {\n    const newSampleArticle = Object.assign({}, sampleArticle);\n    newSampleArticle.images = ['imageLink1', 'imageLink2'];\n\n    const ctx = createMockContext({ request: { body: newSampleArticle } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(newSampleArticle);\n    expect(ctx.body).toMatchObject(newSampleArticle);\n    expect(ctx.throw).not.toBeCalled();\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should throw an error and not add article when invalid data is passed', async () => {\n    articleModel.create = jest.fn((article) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(articleModel.count()).toBe(0);\n  });\n\n  test('should throw an error and not add article when authorUID is missing', async () => {\n    articleModel.create = jest.fn((article) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(articleModel.count()).toBe(0);\n  });\n\n  test('should throw an error and not add article when title is missing', async () => {\n    // articleModel.create = jest.fn(articleModel.create);\n    articleModel.create = jest.fn((article) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await articleController.add(ctx);\n\n    expect(articleModel.create).toBeCalledTimes(1);\n    expect(articleModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(articleModel.count()).toBe(0);\n  });\n});\n\n// #endregion\n\n// #region ArticleController_delete\ndescribe('delete', async () => {\n  const deleteOriginalMockImplementation = articleModel.findByIdAndRemove;\n\n  beforeEach(() => {\n    articleModel.create(sampleArticle);\n    articleModel.findByIdAndRemove.mockClear();\n  });\n\n  afterEach(() => {\n    articleModel.reset();\n    articleModel.findByIdAndRemove = deleteOriginalMockImplementation;\n  });\n\n  test('should delete article successfully when correct id is passed', async () => {\n    const ctx = createMockContext({ params: { id: sampleArticle.id } });\n    const beforeCount = articleModel.count();\n\n    await articleController.delete(ctx);\n\n    expect(articleModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndRemove).toBeCalledWith(sampleArticle.id);\n    expect(ctx.body).toBe(sampleArticle.id);\n    expect(ctx.throw).not.toBeCalled();\n    expect(articleModel.count()).toBe(beforeCount - 1);\n  });\n\n  test('should throw an error when article to delete not found', async () => {\n    articleModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await articleController.delete(ctx);\n\n    expect(articleModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndRemove).toBeCalledWith(555);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when article id passed is null', async () => {\n    articleModel.findByIdAndRemove = jest.fn((id) => {\n      return null;\n    });\n\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await articleController.delete(ctx);\n\n    expect(articleModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndRemove).toBeCalledWith(555);\n    expect(ctx.body).toBeNull();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when id passed is of incorrect type', async () => {\n    articleModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'CastError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 0.9 } });\n\n    await articleController.delete(ctx);\n\n    expect(articleModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndRemove).toBeCalledWith(0.9);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw a 500 error and return null for any other errors caught', async () => {\n    articleModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 123 } });\n\n    await articleController.delete(ctx);\n\n    expect(articleModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndRemove).toBeCalledWith(123);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n  });\n});\n// #endregion\n\n// #region ArticleController_find\n\ndescribe('find', async () => {\n  afterEach(() => {\n    articleModel.find.mockClear();\n    articleModel.reset();\n  });\n\n  test('should return empty list when no data present', async () => {\n    const ctx = createMockContext();\n    await articleController.find(ctx);\n\n    expect(ctx.body).toMatchObject([]);\n    expect(articleModel.find).toBeCalledTimes(1);\n  });\n\n  test('should return values when data present', async () => {\n    articleModel.create(sampleArticle);\n\n    const ctx = createMockContext();\n    await articleController.find(ctx);\n\n    expect(articleModel.find).toBeCalledTimes(1);\n    expect(ctx.body).toMatchObject([sampleArticle]);\n  });\n});\n\n// #endregion\n\n// #region ArticleController_findById\n\ndescribe('findById', async () => {\n  const findByIdOrignialMockImplementation = articleModel.findById;\n\n  beforeEach(() => {\n    articleModel.create(sampleArticle);\n    articleModel.findById.mockClear();\n  });\n\n  afterEach(() => {\n    articleModel.reset();\n    articleModel.findById = findByIdOrignialMockImplementation;\n  });\n\n  test('should return article when correct id is passed', async () => {\n    const ctx = createMockContext({ params: { id: sampleArticle.id } });\n\n    await articleController.findById(ctx);\n\n    expect(articleModel.findById).toBeCalledTimes(1);\n    expect(articleModel.findById).toBeCalledWith(sampleArticle.id);\n    expect(ctx.body).toMatchObject(sampleArticle);\n    expect(ctx.throw).not.toBeCalled();\n  });\n\n  test('should throw an error when id passed doesn\\'t exist', async () => {\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await articleController.findById(ctx);\n\n    expect(articleModel.findById).toBeCalledTimes(1);\n    expect(articleModel.findById).toBeCalledWith(555);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404, 'Article Not Found');\n  });\n\n  test('should throw an error when id passed is null', async () => {\n    articleModel.findById = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: null } });\n\n    await articleController.findById(ctx);\n\n    expect(articleModel.findById).toBeCalledTimes(1);\n    expect(articleModel.findById).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when id passed is of incorrect type', async () => {\n    articleModel.findById = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'CastError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 0.99 } });\n\n    await articleController.findById(ctx);\n\n    expect(articleModel.findById).toBeCalledTimes(1);\n    expect(articleModel.findById).toBeCalledWith(0.99);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw a 500 error and return null for any other errors caught', async () => {\n    articleModel.findById = jest.fn((id) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ params: { id: 123 } });\n\n    await articleController.findById(ctx);\n\n    expect(articleModel.findById).toBeCalledTimes(1);\n    expect(articleModel.findById).toBeCalledWith(123);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n  });\n});\n\n// #endregion\n\n// #region ArticleController_update\ndescribe('update', async () => {\n  const updateOriginalMockImplemenation = articleModel.findByIdAndUpdate;\n\n  beforeEach(() => {\n    articleModel.findByIdAndUpdate.mockClear();\n    articleModel.create(sampleArticle);\n  });\n\n  afterEach(() => {\n    articleModel.reset();\n    articleModel.findByIdAndUpdate = updateOriginalMockImplemenation;\n  });\n\n  test('should update article correctly when valid id and data are passed', async () => {\n    const newSampleArticle = Object.assign({}, sampleArticle);\n    newSampleArticle.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: sampleArticle.id },\n        request: { body: newSampleArticle },\n      },\n    );\n\n    await articleController.update(ctx);\n\n    expect(articleModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndUpdate).toBeCalledWith(sampleArticle.id, newSampleArticle);\n    expect(articleModel.findById(sampleArticle.id).title).toBe(newSampleArticle.title);\n    expect(ctx.throw).not.toBeCalled();\n    expect(ctx.body).toBe(newSampleArticle);\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should throw an error when article not found', async () => {\n    articleModel.findByIdAndUpdate = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const newSampleArticle = Object.assign({}, sampleArticle);\n    newSampleArticle.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 1234 },\n        request: { body: newSampleArticle },\n      },\n    );\n\n    await articleController.update(ctx);\n\n    expect(articleModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndUpdate).toBeCalledWith(1234, newSampleArticle);\n    expect(articleModel.findById(sampleArticle.id)).toBe(sampleArticle);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n    expect(ctx.body).toBeUndefined();\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should throw an error when model returns null', async () => {\n    articleModel.findByIdAndUpdate = jest.fn((id) => {\n      return null;\n    });\n\n    const newSampleArticle = Object.assign({}, sampleArticle);\n    newSampleArticle.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 123 },\n        request: { body: newSampleArticle },\n      },\n    );\n\n    await articleController.update(ctx);\n\n    expect(articleModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndUpdate).toBeCalledWith(123, newSampleArticle);\n    expect(articleModel.findById(sampleArticle.id)).toBe(sampleArticle);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n    expect(ctx.body).toBeNull();\n    expect(articleModel.count()).toBe(1);\n  });\n\n  test('should throw an error 500 for any other issues found', async () => {\n    articleModel.findByIdAndUpdate = jest.fn((id) => {\n      const error = new Error();\n      throw error;\n    });\n\n    const newSampleArticle = Object.assign({}, sampleArticle);\n    newSampleArticle.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 1234 },\n        request: { body: newSampleArticle },\n      },\n    );\n\n    await articleController.update(ctx);\n\n    expect(articleModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(articleModel.findByIdAndUpdate).toBeCalledWith(1234, newSampleArticle);\n    expect(articleModel.findById(sampleArticle.id)).toBe(sampleArticle);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n    expect(ctx.body).toBeUndefined();\n    expect(articleModel.count()).toBe(1);\n  });\n});\n// #endregion\n\n// #endregion\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/article.model.test.js",
    "content": "/* eslint-disable global-require */\nconst mongoose = require('mongoose');\n\nconst mockSchema = jest.fn();\nconst mockModel = jest.fn((modelName, schema) => ({ modelName, schema }));\n\nmongoose.model = mockModel;\nmongoose.Schema = mockSchema;\n\ndescribe('Article Model', () => {\n  test('Should have the correct article name', () => {\n    const model = require('../../src/models/article.model');\n    expect(model.modelName).toBe('Article');\n  });\n\n  test('Schema should contain the required fields', () => {\n    require('../../src/models/article.model');\n    expect(mockSchema).toBeCalledTimes(1);\n    const schema = mockSchema.mock.calls[0][0];\n    expect(Object.keys(schema).length).toBe(10);\n    expect(schema.authorUID).toBeDefined();\n    expect(schema.createdDate).toBeDefined();\n    expect(schema.updatedDate).toBeDefined();\n    expect(schema.title).toBeDefined();\n    expect(schema.description).toBeDefined();\n    expect(schema.body).toBeDefined();\n    expect(schema.meta).toBeDefined();\n    expect(schema.status).toBeDefined();\n    expect(schema.imagesUID).toBeDefined();\n    expect(schema.tags).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/article.routes.test.js",
    "content": "jest.mock('../../src/controllers/article.controller');\njest.mock('../../src/middlewares/jwt');\n\nconst request = require('supertest');\nconst Koa = require('koa');\nconst articleRoutes = require('../../src/routes/article.routes');\nconst articleController = require('../../src/controllers/article.controller');\n\nconst app = new Koa().use(articleRoutes.routes());\n\ndescribe('GET /api/articles', () => {\n  test('Should sucessfully get status 200', async () => {\n    const response = await request(app.callback()).get('/api/articles');\n\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('');\n    expect(articleController.find).toBeCalledTimes(1);\n  });\n});\n\ndescribe('GET /api/articles/:id', () => {\n  test('Should sucessfully get status 200', async () => {\n    const response = await request(app.callback()).get('/api/articles/123');\n\n    expect(articleController.findById).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n  });\n});\n\ndescribe('POST /api/articles', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).post('/api/articles');\n\n    expect(articleController.add).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('');\n    done();\n  });\n});\n\ndescribe('PUT /api/articles/:id', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).put('/api/articles/123');\n\n    expect(articleController.update).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n    done();\n  });\n});\n\ndescribe('DELETE /api/articles/:id', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).delete('/api/articles/123');\n\n    expect(articleController.delete).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n    done();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/config.test.js",
    "content": "const config = require('../../src/environment/config');\n\ndescribe('config', () => {\n  test('should load default values', () => {\n    expect(config.name).not.toBeNull();\n    expect(config.port).not.toBeNull();\n    expect(config.baseAPIRoute).not.toBeNull();\n    expect(config.environment).not.toBeNull();\n    expect(config.messagebus).not.toBeNull();\n    expect(config.db.uri).not.toBeNull();\n    expect(config.db.username).not.toBeNull();\n    expect(config.db.password).not.toBeNull();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/articles-management/tests/unit/server.test.js",
    "content": "/* eslint-disable global-require */\n\nconst mongoose = require('mongoose');\nconst app = require('../../src/app');\nconst config = require('../../src/environment/config');\n\nconst consoleObj = console;\nconst consoleLogMock = jest.fn();\n\nconst mockConnectDB = jest.fn();\nconst mockListen = jest.fn((port, startedMessage) => {\n  startedMessage();\n});\n\nmongoose.connect = mockConnectDB;\napp.listen = mockListen;\nconsoleObj.log = consoleLogMock;\n\nafterEach(() => {\n  mockListen.mockReset();\n  mockConnectDB.mockReset();\n  consoleLogMock.mockReset();\n});\n\ntest('Server works', async () => {\n  require('../../src/server');\n\n  expect(mockConnectDB.mock.calls.length).toBe(1);\n  expect(mockConnectDB.mock.calls[0][0]).toBe(config.db.uri);\n  expect(mockConnectDB.mock.calls[0][1].user).toBe(config.db.username);\n  expect(mockConnectDB.mock.calls[0][1].pass).toBe(config.db.password);\n\n  expect(mockListen.mock.calls.length).toBe(1);\n  expect(mockListen.mock.calls[0][0]).toBe(config.port);\n  expect(mockListen.mock.calls[0][1]).not.toBeNull();\n\n  expect(consoleLogMock.mock.calls.length).toBe(1);\n  expect(consoleLogMock.mock.calls[0][0]).toBe(config.startedMessage);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/.dockerignore",
    "content": "node_modules\npackage-lock.json\n.env"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/.eslintrc.yml",
    "content": "extends: airbnb-base\nenv:\n  jest: true\n\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/.gitignore",
    "content": "node_modules\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/.gitkeep",
    "content": ""
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/.snyk",
    "content": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\n# patches apply the minimum changes required to fix a vulnerability\npatch:\n  SNYK-JS-LODASH-567746:\n    - winston > async > lodash:\n        patched: '2020-08-04T12:02:15.835Z'\n    - mongoose > async > lodash:\n        patched: '2020-08-04T12:02:15.835Z'\n    - amqp-ts-async > winston > async > lodash:\n        patched: '2020-08-04T12:02:15.835Z'\n    - amqp-ts-async > @types/winston > winston > async > lodash:\n        patched: '2020-08-04T12:02:15.835Z'\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/Dockerfile",
    "content": "# Use Node v11.2 as the base image.\nFROM node:11.2.0-alpine\n\n#Set the working directory\nWORKDIR /usr/app\n\n# Copy everything in current directory to /server folder\nADD . /server\n\n# Install dependencies\nRUN cd /server; \\\n    npm install\n\nEXPOSE 3000\n\n# Run node \nCMD [\"node\", \"/server/src/server.js\"]"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/package.json",
    "content": "{\n  \"name\": \"authentication\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Authentication Service - Responsible for authenticating users and providing access tokens\",\n  \"main\": \"./src/server.js\",\n  \"scripts\": {\n    \"start\": \"node ./src/server.js\",\n    \"test\": \"jest --coverage\",\n    \"watch\": \"jest --coverage --watchAll\",\n    \"lint\": \"eslint ./src && eslint ./tests\",\n    \"testOnly\": \"jest\",\n    \"checkCodeQuality\": \"eslint ./src && eslint ./tests && jest --coverage\",\n    \"snyk-protect\": \"snyk protect\",\n    \"prepare\": \"npm run snyk-protect\"\n  },\n  \"jest\": {\n    \"testEnvironment\": \"node\",\n    \"verbose\": true,\n    \"coverageThreshold\": {\n      \"global\": {\n        \"branches\": 100,\n        \"functions\": 100,\n        \"lines\": 100,\n        \"statements\": -10\n      }\n    }\n  },\n  \"author\": \"Rithin Chalumuri\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"amqp-ts-async\": \"^1.3.7\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"dotenv\": \"^6.1.0\",\n    \"jsonwebtoken\": \"^8.5.1\",\n    \"koa\": \"^2.13.0\",\n    \"koa-bodyparser\": \"^4.3.0\",\n    \"koa-helmet\": \"^4.2.1\",\n    \"koa-logger\": \"^3.2.1\",\n    \"koa-router\": \"^7.4.0\",\n    \"mongoose\": \"^5.9.26\",\n    \"winston\": \"^3.3.3\",\n    \"snyk\": \"^1.369.3\"\n  },\n  \"devDependencies\": {\n    \"eslint\": \"^5.9.0\",\n    \"eslint-config-airbnb-base\": \"^13.1.0\",\n    \"eslint-plugin-import\": \"^2.14.0\",\n    \"jest\": \"^23.6.0\",\n    \"supertest\": \"^3.3.0\"\n  },\n  \"snyk\": true\n}\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/app.js",
    "content": "// Import the required npm packages\nconst Koa = require('koa');\nconst Logger = require('koa-logger');\nconst Helmet = require('koa-helmet');\nconst BodyParser = require('koa-bodyparser');\n\n// Get the API routes  file\nconst authRouter = require('./routes/auth.routes');\n\n// Init Koa API App\nconst app = new Koa();\napp.use(Logger());\napp.use(BodyParser());\napp.use(Helmet());\n\n// Setup the API routes\napp.use(authRouter.routes()).use(authRouter.allowedMethods({ throw: true }));\n\nmodule.exports = app;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/controllers/auth.controller.js",
    "content": "const logger = require('winston');\nconst jwt = require('jsonwebtoken');\nconst bcrypt = require('bcryptjs');\nconst Auth = require('../models/auth.model');\nconst config = require('../environment/config');\n\nconst authController = {\n  authenticate: async (ctx) => {\n    try {\n      const user = await Auth.findOne({ emailAddress: ctx.request.body.emailAddress });\n      if (!user) ctx.throw(404);\n      if (!(bcrypt.compareSync(ctx.request.body.password, user.password))) {\n        ctx.body = { auth: false, token: null };\n      } else {\n        const token = jwt.sign({ id: user.emailAddress, role: user.role }, config.jwtsecret, {\n          expiresIn: 86400, // expires in 24 hours\n        });\n        ctx.body = { auth: true, token };\n      }\n    } catch (err) {\n      ctx.throw(500);\n    }\n  },\n\n  add: async (message) => {\n    let user;\n    try {\n      user = JSON.parse(message.content.toString());\n      const hashedPassword = bcrypt.hashSync(user.password, 8);\n      await Auth.create({\n        role: user.role,\n        emailAddress: user.emailAddress,\n        password: hashedPassword,\n      });\n      logger.info(`user auth record created - ${user.emailAddress}`);\n    } catch (err) {\n      logger.error(`Error creating auth record for user ${user.emailAddress} : ${err}`);\n    }\n  },\n};\n\nmodule.exports = authController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/environment/config.js",
    "content": "const config = {\n  name: 'Authentication Service',\n  baseAPIRoute: 'api',\n  port: process.env.PORT || 8080,\n  messagebus: process.env.MESSAGE_BUS || 'amqp://rabbitmq',\n  environment: process.env.ENVIRONMENT || 'dev',\n  db: {\n    uri: process.env.DB_URI\n  },\n  jwtsecret: 'yoursecretkey',\n};\n\nconfig.startedMessage = `${config.name} is running on port ${config.port}/`;\n\nmodule.exports = config;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/message-bus/recieve/user.added.js",
    "content": "const logger = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../../environment/config');\nconst authController = require('../../controllers/auth.controller');\n\nconst exchangeName = 'user.added';\nconst queueName = '';\n\nconst connection = new amqp.Connection(config.messagebus);\nconst exchange = connection.declareExchange(exchangeName, 'fanout', { durable: false });\nconst queue = connection.declareQueue(queueName, { exclusive: true });\nqueue.bind(exchange);\n\nmodule.exports = {\n  start: () => {\n    try {\n      queue.activateConsumer(authController.add);\n    } catch (err) {\n      logger.error(`Error Listening to ${exchangeName}, ${queueName}: ${err}`);\n    }\n  },\n};\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/models/auth.model.js",
    "content": "const mongoose = require('mongoose');\n\nconst AuthSchema = new mongoose.Schema({\n  createdDate: { type: Date, default: Date.now },\n  updatedDate: { type: Date, default: Date.now },\n  emailAddress: { type: String, require: true },\n  password: { type: String, require: true },\n  role: { type: String, require: true, default: 'regular' },\n  status: { type: String, default: 'active' },\n});\n\nmodule.exports = mongoose.model('Auth', AuthSchema);\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/routes/auth.routes.js",
    "content": "const KoaRouter = require('koa-router');\nconst config = require('../environment/config');\nconst authController = require('../controllers/auth.controller');\n\nconst api = 'auth';\n\nconst router = new KoaRouter();\n\nrouter.prefix(`/${config.baseAPIRoute}/${api}`);\n\n// POST /api/auth\nrouter.post('/', authController.authenticate);\n\nmodule.exports = router;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/authentication/src/server.js",
    "content": "/* eslint-disable no-console */\n\n// Init the environment variables and server configurations\nrequire('dotenv').config();\n\n// Import the required packages\nconst Mongoose = require('mongoose');\nconst config = require('./environment/config');\nconst app = require('./app');\n\n// Init Database Connection\nMongoose.connect('mongodb://mongo/test');\nMongoose.connection.on('error', console.error);\n\n// Start Listening to Subscribed Events\nrequire('./message-bus/recieve/user.added').start();\n\n// Run the API Server\napp.listen(config.port, () => {\n  console.log(config.startedMessage);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/.dockerignore",
    "content": "node_modules\npackage-lock.json\n.env"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/.eslintrc.yml",
    "content": "extends: airbnb-base\nenv:\n  jest: true\n\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/.gitignore",
    "content": "node_modules\npackage-lock.json\n.env\ncoverage"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/Dockerfile",
    "content": "# Use Node v11.2 as the base image.\nFROM node:11.2.0-alpine\n\n#Set the working directory\nWORKDIR /usr/app\n\n# Copy everything in current directory to /server folder\nADD . /server\n\n# Install dependencies\nRUN cd /server; \\\n    npm install\n\nEXPOSE 3000\n\n# Run node \nCMD [\"node\", \"/server/src/server.js\"]"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/package.json",
    "content": "{\n  \"name\": \"events-management\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Events Management Service - reponsible for handling local events related operations\",\n  \"main\": \"./src/server.js\",\n  \"scripts\": {\n    \"start\": \"node ./src/server.js\",\n    \"test\": \"jest --coverage\",\n    \"watch\": \"jest --coverage --watchAll\",\n    \"lint\": \"eslint ./src && eslint ./tests\",\n    \"testOnly\": \"jest\",\n    \"checkCodeQuality\": \"eslint ./src && eslint ./tests && jest --coverage\"\n  },\n  \"jest\": {\n    \"testEnvironment\": \"node\",\n    \"verbose\": true,\n    \"coverageThreshold\": {\n      \"global\": {\n        \"branches\": 100,\n        \"functions\": 100,\n        \"lines\": 100,\n        \"statements\": -10\n      }\n    }\n  },\n  \"author\": \"Rithin Chalumuri\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dotenv\": \"^6.1.0\",\n    \"koa\": \"^2.6.2\",\n    \"koa-bodyparser\": \"^4.2.1\",\n    \"koa-helmet\": \"^4.0.0\",\n    \"koa-jwt\": \"^3.5.1\",\n    \"koa-logger\": \"^3.2.0\",\n    \"koa-router\": \"^7.4.0\",\n    \"mongoose\": \"^5.3.13\"\n  },\n  \"devDependencies\": {\n    \"eslint\": \"^5.9.0\",\n    \"eslint-config-airbnb-base\": \"^13.1.0\",\n    \"eslint-plugin-import\": \"^2.14.0\",\n    \"jest\": \"^23.6.0\",\n    \"supertest\": \"^3.3.0\"\n  }\n}\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/app.js",
    "content": "// Import the required npm packages\nconst Koa = require('koa');\nconst Logger = require('koa-logger');\nconst Helmet = require('koa-helmet');\nconst BodyParser = require('koa-bodyparser');\n\n// Get the API routes  file\nconst eventRouter = require('./routes/event.routes');\n\n// Init Koa API App\nconst app = new Koa();\napp.use(Logger());\napp.use(BodyParser());\napp.use(Helmet());\n\n// Setup the API routes\napp.use(eventRouter.routes()).use(eventRouter.allowedMethods({ throw: true }));\n\nmodule.exports = app;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/controllers/__mocks__/event.controller.js",
    "content": "const eventController = {};\n\neventController.find = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = '';\n});\n\neventController.findById = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\neventController.add = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = '';\n});\n\neventController.update = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\neventController.delete = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\nmodule.exports = eventController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/controllers/event.controller.js",
    "content": "const Events = require('../models/event.model');\n\nconst eventController = {\n  find: async (ctx) => {\n    ctx.body = await Events.find();\n  },\n\n  findById: async (ctx) => {\n    try {\n      const result = await Events.findById(ctx.params.id);\n      if (!result) {\n        ctx.throw(404, 'Event Not Found');\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n\n  add: async (ctx) => {\n    try {\n      const newEvent = await Events.create(ctx.request.body);\n      ctx.body = newEvent;\n    } catch (err) {\n      ctx.throw(422);\n    }\n  },\n\n  update: async (ctx) => {\n    try {\n      const result = await Events.findByIdAndUpdate(\n        ctx.params.id,\n        ctx.request.body,\n      );\n      if (!result) {\n        ctx.throw(404);\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n\n  delete: async (ctx) => {\n    try {\n      const result = await Events.findByIdAndRemove(ctx.params.id);\n      if (!result) {\n        ctx.throw(404);\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n};\n\nmodule.exports = eventController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/environment/config.js",
    "content": "const config = {\n  name: 'Events Management Service',\n  baseAPIRoute: 'api',\n  port: process.env.PORT || 8080,\n  messagebus: process.env.MESSAGE_BUS || 'amqp://rabbitmq',\n  environment: process.env.ENVIRONMENT || 'dev',\n  db: {\n    uri: process.env.DB_URI\n  },\n  services: {\n  },\n  jwtsecret: 'yoursecretkey',\n};\n\nconfig.startedMessage = `${config.name} is running on port ${config.port}/`;\n\nmodule.exports = config;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/middlewares/__mocks__/jwt.js",
    "content": "const jwt = jest.fn((ctx, next) => {\n  next();\n});\n\nmodule.exports = jwt;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/middlewares/jwt.js",
    "content": "const koaJwt = require('koa-jwt');\nconst config = require('../environment/config');\n\nmodule.exports = koaJwt({\n  secret: config.jwtsecret,\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/models/__mocks__/event.model.js",
    "content": "/* eslint-disable arrow-body-style */\n\nconst eventModel = {};\n\nlet data = [];\n\neventModel.find = jest.fn(() => data);\n\neventModel.findById = jest.fn((id) => {\n  return data.find(event => event.id === id);\n});\n\neventModel.create = jest.fn((event) => {\n  data.push(event);\n  return event;\n});\n\neventModel.findByIdAndUpdate = jest.fn((id, updatedEvent) => {\n  const index = data.findIndex(event => event.id === id);\n  if (index >= 0) {\n    data[index] = updatedEvent;\n  }\n  return updatedEvent;\n});\n\neventModel.findByIdAndRemove = jest.fn((id) => {\n  const index = data.findIndex(event => event.id === id);\n  data.splice(index, 1);\n  return id;\n});\n\neventModel.count = () => data.length;\neventModel.reset = () => { data = []; };\n\nmodule.exports = eventModel;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/models/event.model.js",
    "content": "const mongoose = require('mongoose');\n\nconst EventSchema = new mongoose.Schema({\n  authorUID: { type: String, require: true },\n  createdDate: { type: Date, default: Date.now },\n  updatedDate: { type: Date, default: Date.now },\n  eventDate: { type: Date, require: true },\n  title: { type: String, require: true },\n  description: { type: String, require: true },\n  body: { type: String, require: true },\n  meta: {\n    attending: { type: Number, default: 0 },\n  },\n  status: { type: Number },\n  imagesUID: [String],\n  tags: [String],\n});\n\nmodule.exports = mongoose.model('Event', EventSchema);\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/routes/event.routes.js",
    "content": "const KoaRouter = require('koa-router');\nconst config = require('../environment/config');\nconst eventsController = require('../controllers/event.controller');\nconst jwt = require('../middlewares/jwt');\n\nconst api = 'events';\n\nconst router = new KoaRouter();\n\nrouter.prefix(`/${config.baseAPIRoute}/${api}`);\n\n// GET /api/events\nrouter.get('/', eventsController.find);\n\n// POST /api/events\nrouter.post('/', eventsController.add);\n\n// GET /api/events/id\nrouter.get('/:id', eventsController.findById);\n\n// PUT /api/events/id\nrouter.put('/:id', eventsController.update);\n\n// DELETE /api/events/id\nrouter.delete('/:id', eventsController.delete);\n\nmodule.exports = router;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/src/server.js",
    "content": "/* eslint-disable no-console */\n\n// Init the environment variables and server configurations\nrequire('dotenv').config();\n\n// Import the required packages\nconst Mongoose = require('mongoose');\nconst config = require('./environment/config');\nconst app = require('./app');\n\n// Init Database Connection\nMongoose.connect('mongodb://mongo/test');\nMongoose.connection.on('error', console.error);\n\n// Run the API Server\napp.listen(config.port, () => {\n  console.log(config.startedMessage);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/tests/unit/app.test.js",
    "content": "/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\n\nconst Koa = require('koa');\nconst eventRouter = require('../../src/routes/event.routes');\n\nconst mockEventRoutes = jest.fn(() => { return async (ctx, next) => {}; });\neventRouter.routes = mockEventRoutes;\n\ndescribe('Koa App', () => {\n  test('Should return valid koa application', () => {\n    const app = require('../../src/app');\n    expect(app).toBeInstanceOf(Koa);\n  });\n\n  test('Should have article routes', () => {\n    require('../../src/app');\n    expect(mockEventRoutes.mock.calls.length).toBe(1);\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/tests/unit/config.test.js",
    "content": "const config = require('../../src/environment/config');\n\ndescribe('config', () => {\n  test('should load default values', () => {\n    expect(config.name).not.toBeNull();\n    expect(config.port).not.toBeNull();\n    expect(config.baseAPIRoute).not.toBeNull();\n    expect(config.environment).not.toBeNull();\n    expect(config.messagebus).not.toBeNull();\n    expect(config.db.uri).not.toBeNull();\n    expect(config.db.username).not.toBeNull();\n    expect(config.db.password).not.toBeNull();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/tests/unit/event.controller.test.js",
    "content": "// #region Disabled ESLint Rules...\n\n/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n\n// #endregion\n\n// #region Setup Mocks...\n\njest.mock('../../src/models/event.model');\n\n// #endregion\n\n// #region Imports...\n\nconst eventModel = require('../../src/models/event.model');\nconst eventController = require('../../src/controllers/event.controller');\n\n// #endregion\n\n// #region Methods...\nconst sampleEvent = {\n  id: 123,\n  title: 'Test Event',\n};\n\nconst createMockContext = (context = {}) => {\n  const ctx = context;\n  ctx.throw = jest.fn((errorCode) => {});\n  return ctx;\n};\n\n// #endregion\n\n// #region Unit Tests...\n\n// #region EventController_add\n\ndescribe('add', async () => {\n  const createMockOriginalImplementation = eventModel.create;\n\n  beforeEach(() => {\n    eventModel.create.mockClear();\n  });\n\n  afterEach(() => {\n    eventModel.reset();\n    eventModel.create = createMockOriginalImplementation;\n  });\n\n  test('should add event when valid data is passed', async () => {\n    const ctx = createMockContext({ request: { body: sampleEvent } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(sampleEvent);\n    expect(ctx.body).toMatchObject(sampleEvent);\n    expect(ctx.throw).not.toBeCalled();\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should add event successfully with multiple tags', async () => {\n    const newsampleEvent = Object.assign({}, sampleEvent);\n    newsampleEvent.tags = ['Sample', 'event'];\n\n    const ctx = createMockContext({ request: { body: newsampleEvent } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(newsampleEvent);\n    expect(ctx.body).toMatchObject(newsampleEvent);\n    expect(ctx.throw).not.toBeCalled();\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should add event successfully without images', async () => {\n    const ctx = createMockContext({ request: { body: sampleEvent } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(sampleEvent);\n    expect(ctx.body).toMatchObject(sampleEvent);\n    expect(ctx.throw).not.toBeCalled();\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should add event successfully with images', async () => {\n    const newsampleEvent = Object.assign({}, sampleEvent);\n    newsampleEvent.images = ['imageLink1', 'imageLink2'];\n\n    const ctx = createMockContext({ request: { body: newsampleEvent } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(newsampleEvent);\n    expect(ctx.body).toMatchObject(newsampleEvent);\n    expect(ctx.throw).not.toBeCalled();\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should throw an error and not add event when invalid data is passed', async () => {\n    eventModel.create = jest.fn((event) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(eventModel.count()).toBe(0);\n  });\n\n  test('should throw an error and not add event when authorUID is missing', async () => {\n    eventModel.create = jest.fn((event) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(eventModel.count()).toBe(0);\n  });\n\n  test('should throw an error and not add event when title is missing', async () => {\n    // eventModel.create = jest.fn(eventModel.create);\n    eventModel.create = jest.fn((event) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await eventController.add(ctx);\n\n    expect(eventModel.create).toBeCalledTimes(1);\n    expect(eventModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(eventModel.count()).toBe(0);\n  });\n});\n\n// #endregion\n\n// #region EventController_delete\ndescribe('delete', async () => {\n  const deleteOriginalMockImplementation = eventModel.findByIdAndRemove;\n\n  beforeEach(() => {\n    eventModel.create(sampleEvent);\n    eventModel.findByIdAndRemove.mockClear();\n  });\n\n  afterEach(() => {\n    eventModel.reset();\n    eventModel.findByIdAndRemove = deleteOriginalMockImplementation;\n  });\n\n  test('should delete event successfully when correct id is passed', async () => {\n    const ctx = createMockContext({ params: { id: sampleEvent.id } });\n    const beforeCount = eventModel.count();\n\n    await eventController.delete(ctx);\n\n    expect(eventModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndRemove).toBeCalledWith(sampleEvent.id);\n    expect(ctx.body).toBe(sampleEvent.id);\n    expect(ctx.throw).not.toBeCalled();\n    expect(eventModel.count()).toBe(beforeCount - 1);\n  });\n\n  test('should throw an error when event to delete not found', async () => {\n    eventModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await eventController.delete(ctx);\n\n    expect(eventModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndRemove).toBeCalledWith(555);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when event id passed is null', async () => {\n    eventModel.findByIdAndRemove = jest.fn((id) => {\n      return null;\n    });\n\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await eventController.delete(ctx);\n\n    expect(eventModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndRemove).toBeCalledWith(555);\n    expect(ctx.body).toBeNull();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when id passed is of incorrect type', async () => {\n    eventModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'CastError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 0.9 } });\n\n    await eventController.delete(ctx);\n\n    expect(eventModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndRemove).toBeCalledWith(0.9);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw a 500 error and return null for any other errors caught', async () => {\n    eventModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 123 } });\n\n    await eventController.delete(ctx);\n\n    expect(eventModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndRemove).toBeCalledWith(123);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n  });\n});\n// #endregion\n\n// #region EventController_find\n\ndescribe('find', async () => {\n  afterEach(() => {\n    eventModel.find.mockClear();\n    eventModel.reset();\n  });\n\n  test('should return empty list when no data present', async () => {\n    const ctx = createMockContext();\n    await eventController.find(ctx);\n\n    expect(ctx.body).toMatchObject([]);\n    expect(eventModel.find).toBeCalledTimes(1);\n  });\n\n  test('should return values when data present', async () => {\n    eventModel.create(sampleEvent);\n\n    const ctx = createMockContext();\n    await eventController.find(ctx);\n\n    expect(eventModel.find).toBeCalledTimes(1);\n    expect(ctx.body).toMatchObject([sampleEvent]);\n  });\n});\n\n// #endregion\n\n// #region EventController_findById\n\ndescribe('findById', async () => {\n  const findByIdOrignialMockImplementation = eventModel.findById;\n\n  beforeEach(() => {\n    eventModel.create(sampleEvent);\n    eventModel.findById.mockClear();\n  });\n\n  afterEach(() => {\n    eventModel.reset();\n    eventModel.findById = findByIdOrignialMockImplementation;\n  });\n\n  test('should return event when correct id is passed', async () => {\n    const ctx = createMockContext({ params: { id: sampleEvent.id } });\n\n    await eventController.findById(ctx);\n\n    expect(eventModel.findById).toBeCalledTimes(1);\n    expect(eventModel.findById).toBeCalledWith(sampleEvent.id);\n    expect(ctx.body).toMatchObject(sampleEvent);\n    expect(ctx.throw).not.toBeCalled();\n  });\n\n  test('should throw an error when id passed doesn\\'t exist', async () => {\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await eventController.findById(ctx);\n\n    expect(eventModel.findById).toBeCalledTimes(1);\n    expect(eventModel.findById).toBeCalledWith(555);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404, 'Event Not Found');\n  });\n\n  test('should throw an error when id passed is null', async () => {\n    eventModel.findById = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: null } });\n\n    await eventController.findById(ctx);\n\n    expect(eventModel.findById).toBeCalledTimes(1);\n    expect(eventModel.findById).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when id passed is of incorrect type', async () => {\n    eventModel.findById = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'CastError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 0.99 } });\n\n    await eventController.findById(ctx);\n\n    expect(eventModel.findById).toBeCalledTimes(1);\n    expect(eventModel.findById).toBeCalledWith(0.99);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw a 500 error and return null for any other errors caught', async () => {\n    eventModel.findById = jest.fn((id) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ params: { id: 123 } });\n\n    await eventController.findById(ctx);\n\n    expect(eventModel.findById).toBeCalledTimes(1);\n    expect(eventModel.findById).toBeCalledWith(123);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n  });\n});\n\n// #endregion\n\n// #region eventController_update\ndescribe('update', async () => {\n  const updateOriginalMockImplemenation = eventModel.findByIdAndUpdate;\n\n  beforeEach(() => {\n    eventModel.findByIdAndUpdate.mockClear();\n    eventModel.create(sampleEvent);\n  });\n\n  afterEach(() => {\n    eventModel.reset();\n    eventModel.findByIdAndUpdate = updateOriginalMockImplemenation;\n  });\n\n  test('should update event correctly when valid id and data are passed', async () => {\n    const newsampleEvent = Object.assign({}, sampleEvent);\n    newsampleEvent.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: sampleEvent.id },\n        request: { body: newsampleEvent },\n      },\n    );\n\n    await eventController.update(ctx);\n\n    expect(eventModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndUpdate).toBeCalledWith(sampleEvent.id, newsampleEvent);\n    expect(eventModel.findById(sampleEvent.id).title).toBe(newsampleEvent.title);\n    expect(ctx.throw).not.toBeCalled();\n    expect(ctx.body).toBe(newsampleEvent);\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should throw an error when event not found', async () => {\n    eventModel.findByIdAndUpdate = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const newsampleEvent = Object.assign({}, sampleEvent);\n    newsampleEvent.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 1234 },\n        request: { body: newsampleEvent },\n      },\n    );\n\n    await eventController.update(ctx);\n\n    expect(eventModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndUpdate).toBeCalledWith(1234, newsampleEvent);\n    expect(eventModel.findById(sampleEvent.id)).toBe(sampleEvent);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n    expect(ctx.body).toBeUndefined();\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should throw an error when model returns null', async () => {\n    eventModel.findByIdAndUpdate = jest.fn((id) => {\n      return null;\n    });\n\n    const newsampleEvent = Object.assign({}, sampleEvent);\n    newsampleEvent.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 123 },\n        request: { body: newsampleEvent },\n      },\n    );\n\n    await eventController.update(ctx);\n\n    expect(eventModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndUpdate).toBeCalledWith(123, newsampleEvent);\n    expect(eventModel.findById(sampleEvent.id)).toBe(sampleEvent);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n    expect(ctx.body).toBeNull();\n    expect(eventModel.count()).toBe(1);\n  });\n\n  test('should throw an error 500 for any other issues found', async () => {\n    eventModel.findByIdAndUpdate = jest.fn((id) => {\n      const error = new Error();\n      throw error;\n    });\n\n    const newsampleEvent = Object.assign({}, sampleEvent);\n    newsampleEvent.title = 'Title Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 1234 },\n        request: { body: newsampleEvent },\n      },\n    );\n\n    await eventController.update(ctx);\n\n    expect(eventModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(eventModel.findByIdAndUpdate).toBeCalledWith(1234, newsampleEvent);\n    expect(eventModel.findById(sampleEvent.id)).toBe(sampleEvent);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n    expect(ctx.body).toBeUndefined();\n    expect(eventModel.count()).toBe(1);\n  });\n});\n// #endregion\n\n// #endregion\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/tests/unit/event.model.test.js",
    "content": "/* eslint-disable global-require */\nconst mongoose = require('mongoose');\n\nconst mockSchema = jest.fn();\nconst mockModel = jest.fn((modelName, schema) => ({ modelName, schema }));\n\nmongoose.model = mockModel;\nmongoose.Schema = mockSchema;\n\ndescribe('Event Model', () => {\n  test('Should have the correct event name', () => {\n    const model = require('../../src/models/event.model');\n    expect(model.modelName).toBe('Event');\n  });\n\n  test('Schema should contain the required fields', () => {\n    require('../../src/models/event.model');\n    expect(mockSchema).toBeCalledTimes(1);\n    const schema = mockSchema.mock.calls[0][0];\n    expect(Object.keys(schema).length).toBe(11);\n    expect(schema.authorUID).toBeDefined();\n    expect(schema.createdDate).toBeDefined();\n    expect(schema.updatedDate).toBeDefined();\n    expect(schema.title).toBeDefined();\n    expect(schema.description).toBeDefined();\n    expect(schema.body).toBeDefined();\n    expect(schema.meta).toBeDefined();\n    expect(schema.status).toBeDefined();\n    expect(schema.imagesUID).toBeDefined();\n    expect(schema.tags).toBeDefined();\n    expect(schema.eventDate).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/tests/unit/event.routes.test.js",
    "content": "jest.mock('../../src/controllers/event.controller');\njest.mock('../../src/middlewares/jwt');\n\nconst request = require('supertest');\nconst Koa = require('koa');\nconst eventRoutes = require('../../src/routes/event.routes');\nconst eventController = require('../../src/controllers/event.controller');\n\nconst app = new Koa().use(eventRoutes.routes());\n\ndescribe('GET /api/events', () => {\n  test('Should sucessfully get status 200', async () => {\n    const response = await request(app.callback()).get('/api/events');\n\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('');\n    expect(eventController.find).toBeCalledTimes(1);\n  });\n});\n\ndescribe('GET /api/events/:id', () => {\n  test('Should sucessfully get status 200', async () => {\n    const response = await request(app.callback()).get('/api/events/123');\n\n    expect(eventController.findById).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n  });\n});\n\ndescribe('POST /api/events', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).post('/api/events');\n\n    expect(eventController.add).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('');\n    done();\n  });\n});\n\ndescribe('PUT /api/events/:id', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).put('/api/events/123');\n\n    expect(eventController.update).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n    done();\n  });\n});\n\ndescribe('DELETE /api/events/:id', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).delete('/api/events/123');\n\n    expect(eventController.delete).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n    done();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/events-management/tests/unit/server.test.js",
    "content": "/* eslint-disable global-require */\n\nconst mongoose = require('mongoose');\nconst app = require('../../src/app');\nconst config = require('../../src/environment/config');\n\nconst consoleObj = console;\nconst consoleLogMock = jest.fn();\n\nconst mockConnectDB = jest.fn();\nconst mockListen = jest.fn((port, startedMessage) => {\n  startedMessage();\n});\n\nmongoose.connect = mockConnectDB;\napp.listen = mockListen;\nconsoleObj.log = consoleLogMock;\n\nafterEach(() => {\n  mockListen.mockReset();\n  mockConnectDB.mockReset();\n  consoleLogMock.mockReset();\n});\n\ntest('Server works', async () => {\n  require('../../src/server');\n\n  expect(mockConnectDB.mock.calls.length).toBe(1);\n  expect(mockConnectDB.mock.calls[0][0]).toBe(config.db.uri);\n  expect(mockConnectDB.mock.calls[0][1].user).toBe(config.db.username);\n  expect(mockConnectDB.mock.calls[0][1].pass).toBe(config.db.password);\n\n  expect(mockListen.mock.calls.length).toBe(1);\n  expect(mockListen.mock.calls[0][0]).toBe(config.port);\n  expect(mockListen.mock.calls[0][1]).not.toBeNull();\n\n  expect(consoleLogMock.mock.calls.length).toBe(1);\n  expect(consoleLogMock.mock.calls[0][0]).toBe(config.startedMessage);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/media-management/.gitkeep",
    "content": ""
  },
  {
    "path": "event-driven-microservices-docker/services/notification/.eslintrc.yml",
    "content": "extends: airbnb-base\nenv:\n  jest: true\n\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/.gitignore",
    "content": "node_modules\npackage-lock.json\n.env\ncoverage"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/Dockerfile",
    "content": "# Use Node v11.2 as the base image.\nFROM node:11.2.0-alpine\n\n#Set the working directory\nWORKDIR /usr/app\n\n# Copy everything in current directory to /server folder\nADD . /server\n\n# Install dependencies\nRUN cd /server; \\\n    npm install\n\n# Run node \nCMD [\"node\", \"/server/src/server.js\"]"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/__mocks__/amqp-ts-async.js",
    "content": "/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n\n\nconst bind = jest.fn((exchange) => {\n});\n\nconst activateConsumer = jest.fn((onRecieve) => {\n  onRecieve();\n});\n\nconst declareExchange = jest.fn((exchangeName, type, options) => {\n  return exchangeName;\n});\n\nconst declareQueue = jest.fn((exchangeName, type, options) => {\n  return {\n    bind,\n    activateConsumer,\n  };\n});\n\nconst connection = jest.fn((url) => {\n  return {\n    connectionUrl: url,\n    declareExchange,\n    declareQueue,\n  };\n});\n\nmodule.exports.Connection = connection;\nmodule.exports.activateConsumer = activateConsumer;\nmodule.exports.bind = bind;\nmodule.exports.declareExchange = declareExchange;\nmodule.exports.declareQueue = declareQueue;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/__mocks__/koa.js",
    "content": "const appListen = jest.fn(() => {\n\n});\n\nmodule.exports = jest.fn(() => ({\n  listen: appListen,\n}));\n\nmodule.exports.appListen = appListen;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/__mocks__/nodemailer.js",
    "content": "/* eslint-disable no-unused-vars */\n\nconst lib = {};\n\nconst sendMail = jest.fn(options => true);\n\nlib.createTransport = jest.fn(options => ({\n  sendMail,\n}));\n\nmodule.exports = lib;\nmodule.exports.sendMail = sendMail;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/__mocks__/winston.js",
    "content": "/* eslint-disable no-unused-vars */\n\nmodule.exports.info = jest.fn((message) => {\n});\n\nmodule.exports.error = jest.fn((message) => {\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/package.json",
    "content": "{\n  \"name\": \"notification\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Notifications Service (Internal)  - Reposible to send out notifications to users regarding various topics\",\n  \"main\": \"./src/server.js\",\n  \"scripts\": {\n    \"start\": \"node ./src/server.js\",\n    \"test\": \"jest --coverage\",\n    \"watch\": \"jest --coverage --watchAll\",\n    \"lint\": \"eslint ./src && eslint ./tests\",\n    \"testOnly\" : \"jest\",\n    \"checkCodeQuality\" : \"eslint ./src && eslint ./tests && jest --coverage\"\n  },\n  \"author\": \"Rithin Chalumuri\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"amqp-ts-async\": \"^1.3.7\",\n    \"dotenv\": \"^6.2.0\",\n    \"koa\": \"^2.6.2\",\n    \"nodemailer\": \"^4.7.0\",\n    \"winston\": \"^3.1.0\"\n  },\n  \"devDependencies\": {\n    \"eslint\": \"^5.9.0\",\n    \"eslint-config-airbnb-base\": \"^13.1.0\",\n    \"eslint-plugin-import\": \"^2.14.0\",\n    \"jest\": \"^23.6.0\",\n    \"supertest\": \"^3.3.0\"\n  }\n}\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/environment/config.js",
    "content": "const config = {\n  name: 'Notification Service',\n  messagebus: process.env.MESSAGE_BUS || 'amqp://guest:guest@localhost',\n  environment: process.env.ENVIRONMENT || 'dev',\n  email: {\n    service: process.env.EMAIL_SERVICE || '',\n    username: process.env.EMAIL_ID || '',\n    password: process.env.EMAIL_PASSWORD || '',\n    adminEmailID: process.env.ADMIN_EMAIL || '',\n  },\n};\n\nconfig.startedMessage = `${config.name} is running`;\n\nmodule.exports = config;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/message-controllers/__mocks__/articles.js",
    "content": "/* eslint-disable no-unused-vars */\nconst controller = {};\n\ncontroller.added = jest.fn(message => true);\n\nmodule.exports = controller;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/message-controllers/articles.js",
    "content": "const logger = require('winston');\nconst emailModule = require('../modules/email/email');\n\nconst controller = {};\n\ncontroller.added = async (message) => {\n  try {\n    const content = JSON.parse(message.content.toString());\n    await emailModule.sendArticleAddedEmail(content);\n  } catch (err) {\n    logger.error(`Error in handling the recieved message - article.added - ${err}`);\n  }\n};\n\nmodule.exports = controller;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/modules/email/__mocks__/email.js",
    "content": "/* eslint-disable no-unused-vars */\nconst email = {};\n\nemail.sendArticleAddedEmail = jest.fn((message) => {\n});\n\nmodule.exports = email;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/modules/email/__mocks__/email.templates.js",
    "content": "const templates = {};\n\ntemplates.GetRenderedArticleAddedEmailHtml = jest.fn((title, description) => `${title}, ${description}`);\n\nmodule.exports = templates;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/modules/email/email.js",
    "content": "const nodemailer = require('nodemailer');\nconst logger = require('winston');\nconst config = require('../../environment/config');\nconst template = require('./email.templates');\n\nconst transporter = nodemailer.createTransport({\n  service: config.email.service,\n  auth: {\n    user: config.email.username,\n    pass: config.email.password,\n  },\n});\n\nconst email = {};\n\nemail.sendArticleAddedEmail = async (message) => {\n  try {\n    const emailHtml = template.GetRenderedArticleAddedEmailHtml(message.title, message.description);\n\n    const mailOptions = {\n      from: config.email.username,\n      to: config.email.adminEmailID,\n      subject: 'LocalNewsApplication - New Article Added!',\n      html: emailHtml,\n    };\n    await transporter.sendMail(mailOptions);\n  } catch (err) {\n    logger.error(`Error sending email ${err}`);\n  }\n};\n\nmodule.exports = email;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/modules/email/email.templates.js",
    "content": "module.exports.GetRenderedArticleAddedEmailHtml = (title, description) => {\n  const name = 'Admin';\n  const line1 = `A new article with the title '${title}' has been to local news web application. It is described as '${description}'`;\n  const buttonText = 'View Article';\n  const buttonLink = '';\n  const unsubscribeLink = '';\n\n  return `\n  <!doctype html>\n  <html>\n    <head>\n      <meta name=\"viewport\" content=\"width=device-width\">\n      <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n      <title>Simple Transactional Email</title>\n      <style>\n      /* -------------------------------------\n          INLINED WITH htmlemail.io/inline\n      ------------------------------------- */\n      /* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n      @media only screen and (max-width: 620px) {\n        table[class=body] h1 {\n          font-size: 28px !important;\n          margin-bottom: 10px !important;\n        }\n        table[class=body] p,\n              table[class=body] ul,\n              table[class=body] ol,\n              table[class=body] td,\n              table[class=body] span,\n              table[class=body] a {\n          font-size: 16px !important;\n        }\n        table[class=body] .wrapper,\n              table[class=body] .article {\n          padding: 10px !important;\n        }\n        table[class=body] .content {\n          padding: 0 !important;\n        }\n        table[class=body] .container {\n          padding: 0 !important;\n          width: 100% !important;\n        }\n        table[class=body] .main {\n          border-left-width: 0 !important;\n          border-radius: 0 !important;\n          border-right-width: 0 !important;\n        }\n        table[class=body] .btn table {\n          width: 100% !important;\n        }\n        table[class=body] .btn a {\n          width: 100% !important;\n        }\n        table[class=body] .img-responsive {\n          height: auto !important;\n          max-width: 100% !important;\n          width: auto !important;\n        }\n      }\n      /* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n      @media all {\n        .ExternalClass {\n          width: 100%;\n        }\n        .ExternalClass,\n              .ExternalClass p,\n              .ExternalClass span,\n              .ExternalClass font,\n              .ExternalClass td,\n              .ExternalClass div {\n          line-height: 100%;\n        }\n        .apple-link a {\n          color: inherit !important;\n          font-family: inherit !important;\n          font-size: inherit !important;\n          font-weight: inherit !important;\n          line-height: inherit !important;\n          text-decoration: none !important;\n        }\n        .btn-primary table td:hover {\n          background-color: #34495e !important;\n        }\n        .btn-primary a:hover {\n          background-color: #34495e !important;\n          border-color: #34495e !important;\n        }\n      }\n      </style>\n    </head>\n    <body class=\"\" style=\"background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;\">\n      <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"body\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;\">\n        <tr>\n          <td style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\">&nbsp;</td>\n          <td class=\"container\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;\">\n            <div class=\"content\" style=\"box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;\">\n  \n              <!-- START CENTERED WHITE CONTAINER -->\n              <span class=\"preheader\" style=\"color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;\">Local News Application - A new article has been added to the website </span>\n              <table class=\"main\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;\">\n  \n                <!-- START MAIN CONTENT AREA -->\n                <tr>\n                  <td class=\"wrapper\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;\">\n                    <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\">\n                      <tr>\n                        <td style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\">\n                          <p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">Hi ${name},</p>\n                          <p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">${line1}</p>\n                          <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"btn btn-primary\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;\">\n                            <tbody>\n                              <tr>\n                                <td align=\"left\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;\">\n                                  <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;\">\n                                    <tbody>\n                                      <tr>\n                                        <td style=\"font-family: sans-serif; font-size: 14px; vertical-align: top; background-color: #3498db; border-radius: 5px; text-align: center;\"> <a href=\"${buttonLink}\" target=\"_blank\" style=\"display: inline-block; color: #ffffff; background-color: #3498db; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-transform: capitalize; border-color: #3498db;\">${buttonText}</a> </td>\n                                      </tr>\n                                    </tbody>\n                                  </table>\n                                </td>\n                              </tr>\n                            </tbody>\n                          </table>\n                        </td>\n                      </tr>\n                    </table>\n                  </td>\n                </tr>\n  \n              <!-- END MAIN CONTENT AREA -->\n              </table>\n  \n              <!-- START FOOTER -->\n              <div class=\"footer\" style=\"clear: both; Margin-top: 10px; text-align: center; width: 100%;\">\n                <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\">\n                  <tr>\n                    <td class=\"content-block\" style=\"font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;\">\n                      <span class=\"apple-link\" style=\"color: #999999; font-size: 12px; text-align: center;\">Local News Application, Coventry, United Kingdom CV1 5GA</span>\n                      <br> Don't like these emails? <a href=\"${unsubscribeLink}\" style=\"text-decoration: underline; color: #999999; font-size: 12px; text-align: center;\">Unsubscribe</a>.\n                    </td>\n                  </tr>\n                </table>\n              </div>\n              <!-- END FOOTER -->\n  \n            <!-- END CENTERED WHITE CONTAINER -->\n            </div>\n          </td>\n          <td style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\">&nbsp;</td>\n        </tr>\n      </table>\n    </body>\n  </html>`;\n};\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/server.js",
    "content": "require('dotenv').config();\nconst logger = require('winston');\nconst Koa = require('koa');\nconst config = require('./environment/config');\n\nrequire('./subscriptions/article.added').start();\n\nconst app = new Koa();\napp.listen();\nlogger.info(config.startedMessage);\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/subscriptions/__mocks__/article.added.js",
    "content": "module.exports.start = jest.fn();\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/src/subscriptions/article.added.js",
    "content": "const logger = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../environment/config');\nconst articleMessageController = require('../message-controllers/articles');\n\nconst exchangeName = 'articles.added';\nconst queueName = '';\n\nconst connection = new amqp.Connection(config.messagebus);\nconst exchange = connection.declareExchange(exchangeName, 'fanout', { durable: false });\nconst queue = connection.declareQueue(queueName, { exclusive: true });\nqueue.bind(exchange);\n\nmodule.exports = {\n  start: () => {\n    try {\n      queue.activateConsumer(articleMessageController.added);\n    } catch (err) {\n      logger.error(`Error Listening to ${exchangeName}, ${queueName}: ${err}`);\n    }\n  },\n};\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/__snapshots__/config.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`config should load default values 1`] = `\nObject {\n  \"email\": Object {\n    \"adminEmailID\": \"\",\n    \"password\": \"\",\n    \"service\": \"\",\n    \"username\": \"\",\n  },\n  \"environment\": \"dev\",\n  \"messagebus\": \"amqp://guest:guest@localhost\",\n  \"name\": \"Notification Service\",\n  \"startedMessage\": \"Notification Service is running\",\n}\n`;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/__snapshots__/email.templates.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Article Added Email Template Should return correct email template 1`] = `\n\"\n  <!doctype html>\n  <html>\n    <head>\n      <meta name=\\\\\"viewport\\\\\" content=\\\\\"width=device-width\\\\\">\n      <meta http-equiv=\\\\\"Content-Type\\\\\" content=\\\\\"text/html; charset=UTF-8\\\\\">\n      <title>Simple Transactional Email</title>\n      <style>\n      /* -------------------------------------\n          INLINED WITH htmlemail.io/inline\n      ------------------------------------- */\n      /* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n      @media only screen and (max-width: 620px) {\n        table[class=body] h1 {\n          font-size: 28px !important;\n          margin-bottom: 10px !important;\n        }\n        table[class=body] p,\n              table[class=body] ul,\n              table[class=body] ol,\n              table[class=body] td,\n              table[class=body] span,\n              table[class=body] a {\n          font-size: 16px !important;\n        }\n        table[class=body] .wrapper,\n              table[class=body] .article {\n          padding: 10px !important;\n        }\n        table[class=body] .content {\n          padding: 0 !important;\n        }\n        table[class=body] .container {\n          padding: 0 !important;\n          width: 100% !important;\n        }\n        table[class=body] .main {\n          border-left-width: 0 !important;\n          border-radius: 0 !important;\n          border-right-width: 0 !important;\n        }\n        table[class=body] .btn table {\n          width: 100% !important;\n        }\n        table[class=body] .btn a {\n          width: 100% !important;\n        }\n        table[class=body] .img-responsive {\n          height: auto !important;\n          max-width: 100% !important;\n          width: auto !important;\n        }\n      }\n      /* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n      @media all {\n        .ExternalClass {\n          width: 100%;\n        }\n        .ExternalClass,\n              .ExternalClass p,\n              .ExternalClass span,\n              .ExternalClass font,\n              .ExternalClass td,\n              .ExternalClass div {\n          line-height: 100%;\n        }\n        .apple-link a {\n          color: inherit !important;\n          font-family: inherit !important;\n          font-size: inherit !important;\n          font-weight: inherit !important;\n          line-height: inherit !important;\n          text-decoration: none !important;\n        }\n        .btn-primary table td:hover {\n          background-color: #34495e !important;\n        }\n        .btn-primary a:hover {\n          background-color: #34495e !important;\n          border-color: #34495e !important;\n        }\n      }\n      </style>\n    </head>\n    <body class=\\\\\"\\\\\" style=\\\\\"background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;\\\\\">\n      <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" class=\\\\\"body\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;\\\\\">\n        <tr>\n          <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top;\\\\\">&nbsp;</td>\n          <td class=\\\\\"container\\\\\" style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;\\\\\">\n            <div class=\\\\\"content\\\\\" style=\\\\\"box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;\\\\\">\n  \n              <!-- START CENTERED WHITE CONTAINER -->\n              <span class=\\\\\"preheader\\\\\" style=\\\\\"color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;\\\\\">Local News Application - A new article has been added to the website </span>\n              <table class=\\\\\"main\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;\\\\\">\n  \n                <!-- START MAIN CONTENT AREA -->\n                <tr>\n                  <td class=\\\\\"wrapper\\\\\" style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;\\\\\">\n                    <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\\\\\">\n                      <tr>\n                        <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top;\\\\\">\n                          <p style=\\\\\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\\\\\">Hi Admin,</p>\n                          <p style=\\\\\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\\\\\">A new article with the title 'Test Name' has been to local news web application. It is described as 'Test Text'</p>\n                          <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" class=\\\\\"btn btn-primary\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;\\\\\">\n                            <tbody>\n                              <tr>\n                                <td align=\\\\\"left\\\\\" style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;\\\\\">\n                                  <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;\\\\\">\n                                    <tbody>\n                                      <tr>\n                                        <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; background-color: #3498db; border-radius: 5px; text-align: center;\\\\\"> <a href=\\\\\"\\\\\" target=\\\\\"_blank\\\\\" style=\\\\\"display: inline-block; color: #ffffff; background-color: #3498db; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-transform: capitalize; border-color: #3498db;\\\\\">View Article</a> </td>\n                                      </tr>\n                                    </tbody>\n                                  </table>\n                                </td>\n                              </tr>\n                            </tbody>\n                          </table>\n                        </td>\n                      </tr>\n                    </table>\n                  </td>\n                </tr>\n  \n              <!-- END MAIN CONTENT AREA -->\n              </table>\n  \n              <!-- START FOOTER -->\n              <div class=\\\\\"footer\\\\\" style=\\\\\"clear: both; Margin-top: 10px; text-align: center; width: 100%;\\\\\">\n                <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\\\\\">\n                  <tr>\n                    <td class=\\\\\"content-block\\\\\" style=\\\\\"font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;\\\\\">\n                      <span class=\\\\\"apple-link\\\\\" style=\\\\\"color: #999999; font-size: 12px; text-align: center;\\\\\">Local News Application, Coventry, United Kingdom CV1 5GA</span>\n                      <br> Don't like these emails? <a href=\\\\\"\\\\\" style=\\\\\"text-decoration: underline; color: #999999; font-size: 12px; text-align: center;\\\\\">Unsubscribe</a>.\n                    </td>\n                  </tr>\n                </table>\n              </div>\n              <!-- END FOOTER -->\n  \n            <!-- END CENTERED WHITE CONTAINER -->\n            </div>\n          </td>\n          <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top;\\\\\">&nbsp;</td>\n        </tr>\n      </table>\n    </body>\n  </html>\"\n`;\n\nexports[`Article Added Email Template Should return correct email template when no data is passed 1`] = `\n\"\n  <!doctype html>\n  <html>\n    <head>\n      <meta name=\\\\\"viewport\\\\\" content=\\\\\"width=device-width\\\\\">\n      <meta http-equiv=\\\\\"Content-Type\\\\\" content=\\\\\"text/html; charset=UTF-8\\\\\">\n      <title>Simple Transactional Email</title>\n      <style>\n      /* -------------------------------------\n          INLINED WITH htmlemail.io/inline\n      ------------------------------------- */\n      /* -------------------------------------\n          RESPONSIVE AND MOBILE FRIENDLY STYLES\n      ------------------------------------- */\n      @media only screen and (max-width: 620px) {\n        table[class=body] h1 {\n          font-size: 28px !important;\n          margin-bottom: 10px !important;\n        }\n        table[class=body] p,\n              table[class=body] ul,\n              table[class=body] ol,\n              table[class=body] td,\n              table[class=body] span,\n              table[class=body] a {\n          font-size: 16px !important;\n        }\n        table[class=body] .wrapper,\n              table[class=body] .article {\n          padding: 10px !important;\n        }\n        table[class=body] .content {\n          padding: 0 !important;\n        }\n        table[class=body] .container {\n          padding: 0 !important;\n          width: 100% !important;\n        }\n        table[class=body] .main {\n          border-left-width: 0 !important;\n          border-radius: 0 !important;\n          border-right-width: 0 !important;\n        }\n        table[class=body] .btn table {\n          width: 100% !important;\n        }\n        table[class=body] .btn a {\n          width: 100% !important;\n        }\n        table[class=body] .img-responsive {\n          height: auto !important;\n          max-width: 100% !important;\n          width: auto !important;\n        }\n      }\n      /* -------------------------------------\n          PRESERVE THESE STYLES IN THE HEAD\n      ------------------------------------- */\n      @media all {\n        .ExternalClass {\n          width: 100%;\n        }\n        .ExternalClass,\n              .ExternalClass p,\n              .ExternalClass span,\n              .ExternalClass font,\n              .ExternalClass td,\n              .ExternalClass div {\n          line-height: 100%;\n        }\n        .apple-link a {\n          color: inherit !important;\n          font-family: inherit !important;\n          font-size: inherit !important;\n          font-weight: inherit !important;\n          line-height: inherit !important;\n          text-decoration: none !important;\n        }\n        .btn-primary table td:hover {\n          background-color: #34495e !important;\n        }\n        .btn-primary a:hover {\n          background-color: #34495e !important;\n          border-color: #34495e !important;\n        }\n      }\n      </style>\n    </head>\n    <body class=\\\\\"\\\\\" style=\\\\\"background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;\\\\\">\n      <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" class=\\\\\"body\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;\\\\\">\n        <tr>\n          <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top;\\\\\">&nbsp;</td>\n          <td class=\\\\\"container\\\\\" style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;\\\\\">\n            <div class=\\\\\"content\\\\\" style=\\\\\"box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;\\\\\">\n  \n              <!-- START CENTERED WHITE CONTAINER -->\n              <span class=\\\\\"preheader\\\\\" style=\\\\\"color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;\\\\\">Local News Application - A new article has been added to the website </span>\n              <table class=\\\\\"main\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;\\\\\">\n  \n                <!-- START MAIN CONTENT AREA -->\n                <tr>\n                  <td class=\\\\\"wrapper\\\\\" style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;\\\\\">\n                    <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\\\\\">\n                      <tr>\n                        <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top;\\\\\">\n                          <p style=\\\\\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\\\\\">Hi Admin,</p>\n                          <p style=\\\\\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\\\\\">A new article with the title 'undefined' has been to local news web application. It is described as 'undefined'</p>\n                          <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" class=\\\\\"btn btn-primary\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;\\\\\">\n                            <tbody>\n                              <tr>\n                                <td align=\\\\\"left\\\\\" style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;\\\\\">\n                                  <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;\\\\\">\n                                    <tbody>\n                                      <tr>\n                                        <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top; background-color: #3498db; border-radius: 5px; text-align: center;\\\\\"> <a href=\\\\\"\\\\\" target=\\\\\"_blank\\\\\" style=\\\\\"display: inline-block; color: #ffffff; background-color: #3498db; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-transform: capitalize; border-color: #3498db;\\\\\">View Article</a> </td>\n                                      </tr>\n                                    </tbody>\n                                  </table>\n                                </td>\n                              </tr>\n                            </tbody>\n                          </table>\n                        </td>\n                      </tr>\n                    </table>\n                  </td>\n                </tr>\n  \n              <!-- END MAIN CONTENT AREA -->\n              </table>\n  \n              <!-- START FOOTER -->\n              <div class=\\\\\"footer\\\\\" style=\\\\\"clear: both; Margin-top: 10px; text-align: center; width: 100%;\\\\\">\n                <table border=\\\\\"0\\\\\" cellpadding=\\\\\"0\\\\\" cellspacing=\\\\\"0\\\\\" style=\\\\\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\\\\\">\n                  <tr>\n                    <td class=\\\\\"content-block\\\\\" style=\\\\\"font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;\\\\\">\n                      <span class=\\\\\"apple-link\\\\\" style=\\\\\"color: #999999; font-size: 12px; text-align: center;\\\\\">Local News Application, Coventry, United Kingdom CV1 5GA</span>\n                      <br> Don't like these emails? <a href=\\\\\"\\\\\" style=\\\\\"text-decoration: underline; color: #999999; font-size: 12px; text-align: center;\\\\\">Unsubscribe</a>.\n                    </td>\n                  </tr>\n                </table>\n              </div>\n              <!-- END FOOTER -->\n  \n            <!-- END CENTERED WHITE CONTAINER -->\n            </div>\n          </td>\n          <td style=\\\\\"font-family: sans-serif; font-size: 14px; vertical-align: top;\\\\\">&nbsp;</td>\n        </tr>\n      </table>\n    </body>\n  </html>\"\n`;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/__snapshots__/email.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Email Options Shoud set the correct email credentials 1`] = `\nObject {\n  \"auth\": Object {\n    \"pass\": \"\",\n    \"user\": \"\",\n  },\n  \"service\": \"\",\n}\n`;\n\nexports[`Send Article Added Email Shoud send email when correct details are provided 1`] = `\nObject {\n  \"from\": \"\",\n  \"html\": \"Test Article, Test Text\",\n  \"subject\": \"LocalNewsApplication - New Article Added!\",\n  \"to\": \"\",\n}\n`;\n\nexports[`Send Article Added Email Shoud throw an error when an exception occurs 1`] = `\nObject {\n  \"from\": \"\",\n  \"html\": \"Test Article, Test Text\",\n  \"subject\": \"LocalNewsApplication - New Article Added!\",\n  \"to\": \"\",\n}\n`;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/article.added.subscription.test.js",
    "content": "/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\njest.mock('winston');\njest.mock('amqp-ts-async');\njest.mock('../../src/message-controllers/articles');\n\nconst winston = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../../src/environment/config');\nconst articleMessageController = require('../../src/message-controllers/articles');\n\ndescribe('Message Broker Connection', () => {\n  afterEach(() => {\n    jest.mock('amqp-ts-async');\n  });\n\n  test('Should connect to correct url', () => {\n    require('../../src/subscriptions/article.added');\n    expect(amqp.Connection).toBeCalledTimes(1);\n    expect(amqp.Connection).toBeCalledWith(config.messagebus);\n  });\n\n  test('Should init with correct exchange details', () => {\n    require('../../src/subscriptions/article.added');\n    expect(amqp.declareExchange.mock.calls.length).toBe(1);\n    expect(amqp.declareExchange.mock.calls[0][0]).toBe('articles.added');\n    expect(amqp.declareExchange.mock.calls[0][1]).toBe('fanout');\n  });\n\n  test('Should init correct queue', () => {\n    require('../../src/subscriptions/article.added');\n    expect(amqp.declareQueue.mock.calls.length).toBe(1);\n    expect(amqp.declareQueue.mock.calls[0][0]).toBe('');\n  });\n  test('Should bind the queue to exchange', () => {\n    require('../../src/subscriptions/article.added');\n    expect(amqp.bind.mock.calls.length).toBe(1);\n    expect(amqp.bind.mock.calls[0][0]).toBe('articles.added');\n  });\n});\n\ndescribe('Listening', () => {\n  afterEach(() => {\n    jest.mock('amqp-ts-async');\n    amqp.activateConsumer.mockClear();\n    articleMessageController.added.mockClear();\n  });\n\n  test('Should start listening', () => {\n    require('../../src/subscriptions/article.added').start();\n    expect(amqp.activateConsumer.mock.calls.length).toBe(1);\n    expect(articleMessageController.added).toBeCalledTimes(1);\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should log exception if there is an error when starting listening', () => {\n    articleMessageController.added = jest.fn((msg) => {\n      throw new Error();\n    });\n    require('../../src/subscriptions/article.added').start();\n    expect(amqp.activateConsumer.mock.calls.length).toBe(1);\n    expect(articleMessageController.added).toBeCalledTimes(1);\n    expect(winston.error).toBeCalled();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/article.message.controller.test.js",
    "content": "/* eslint-disable no-unused-vars */\njest.mock('winston');\njest.mock('../../src/modules/email/email');\n\nconst winston = require('winston');\nconst email = require('../../src/modules/email/email');\nconst articleMessageController = require('../../src/message-controllers/articles');\n\nconst message = {\n  content: {\n    title: 'Test Article',\n    description: 'Test Text',\n  },\n};\n\ndescribe('Article Added Message Controller', async () => {\n  afterEach(() => {\n    email.sendArticleAddedEmail.mockClear();\n  });\n\n  test('Should succeed when correct message content is passed', async () => {\n    articleMessageController.added({ content: Buffer.from(JSON.stringify(message.content)) });\n    expect(winston.error).not.toBeCalled();\n    expect(email.sendArticleAddedEmail).toBeCalledTimes(1);\n    expect(email.sendArticleAddedEmail).toBeCalledWith(message.content);\n  });\n\n  test('Should throw an error when correct message content is null', async () => {\n    articleMessageController.added(null);\n    expect(winston.error).toBeCalled();\n    expect(email.sendArticleAddedEmail).not.toBeCalled();\n  });\n\n  test('Should throw an error when sending email fails', async () => {\n    email.sendArticleAddedEmail = jest.fn((content) => {\n      throw new Error();\n    });\n    articleMessageController.added({ content: Buffer.from(JSON.stringify(message.content)) });\n    expect(winston.error).toBeCalled();\n    expect(email.sendArticleAddedEmail).toBeCalledTimes(1);\n    expect(email.sendArticleAddedEmail).toBeCalledWith(message.content);\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/config.test.js",
    "content": "const config = require('../../src/environment/config');\n\ndescribe('config', () => {\n  test('should load default values', () => {\n    expect(config.name).not.toBeNull();\n    expect(config.environment).not.toBeNull();\n    expect(config.messagebus).not.toBeNull();\n    expect(config.email.service).not.toBeNull();\n    expect(config.email.username).not.toBeNull();\n    expect(config.email.password).not.toBeNull();\n    expect(config.email.adminEmailID).not.toBeNull();\n    expect(config).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/email.templates.test.js",
    "content": "const template = require('../../src/modules/email/email.templates');\n\ndescribe('Article Added Email Template', () => {\n  test('Should return correct email template', () => {\n    const html = template.GetRenderedArticleAddedEmailHtml('Test Name', 'Test Text');\n    expect(html).toMatchSnapshot();\n  });\n\n  test('Should return correct email template when no data is passed', () => {\n    const html = template.GetRenderedArticleAddedEmailHtml();\n    expect(html).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/email.test.js",
    "content": "/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\njest.mock('nodemailer');\njest.mock('winston');\njest.mock('../../src/modules/email/email.templates');\n\nconst nodemailer = require('nodemailer');\nconst winston = require('winston');\nconst templates = require('../../src/modules/email/email.templates');\n\nconst message = {\n  title: 'Test Article',\n  description: 'Test Text',\n};\n\ndescribe('Email Options', () => {\n  test('Shoud set the correct email credentials', () => {\n    require('../../src/modules/email/email');\n    expect(nodemailer.createTransport).toBeCalledTimes(1);\n    expect(nodemailer.createTransport.mock.calls[0][0]).toMatchSnapshot();\n    expect(winston.error).not.toBeCalled();\n  });\n});\n\ndescribe('Send Article Added Email', () => {\n  afterEach(() => {\n    templates.GetRenderedArticleAddedEmailHtml.mockClear();\n  });\n\n  test('Shoud send email when correct details are provided', () => {\n    const email = require('../../src/modules/email/email');\n\n    email.sendArticleAddedEmail(message);\n\n    expect(templates.GetRenderedArticleAddedEmailHtml).toBeCalledTimes(1);\n    expect(templates.GetRenderedArticleAddedEmailHtml)\n      .toBeCalledWith(message.title, message.description);\n\n    expect(nodemailer.sendMail.mock.calls.length).toBe(1);\n    expect(nodemailer.sendMail.mock.calls[0][0]).toMatchSnapshot();\n  });\n\n  test('Shoud throw an error when an exception occurs', () => {\n    templates.GetRenderedArticleAddedEmailHtml = jest.fn((title, description) => {\n      throw new Error();\n    });\n\n    const email = require('../../src/modules/email/email');\n\n    email.sendArticleAddedEmail(message);\n\n    expect(templates.GetRenderedArticleAddedEmailHtml).toBeCalledTimes(1);\n    expect(templates.GetRenderedArticleAddedEmailHtml)\n      .toBeCalledWith(message.title, message.description);\n\n    expect(nodemailer.sendMail.mock.calls.length).toBe(1);\n    expect(nodemailer.sendMail.mock.calls[0][0]).toMatchSnapshot();\n\n    expect(winston.error).toBeCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/notification/tests/unit/server.test.js",
    "content": "/* eslint-disable global-require */\njest.mock('../../src/subscriptions/article.added');\njest.mock('koa');\njest.mock('winston');\n\nconst koa = require('koa');\nconst winston = require('winston');\nconst articleAddedSubscription = require('../../src/subscriptions/article.added');\nconst config = require('../../src/environment/config');\n\ntest('Server works', async () => {\n  require('../../src/server');\n  expect(koa.appListen).toBeCalledTimes(1);\n  expect(winston.info).toBeCalledTimes(1);\n  expect(winston.info).toBeCalledWith(config.startedMessage);\n  expect(articleAddedSubscription.start).toBeCalledTimes(1);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/search/.gitkeep",
    "content": ""
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/.dockerignore",
    "content": "node_modules\npackage-lock.json\n.env"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/.eslintrc.yml",
    "content": "extends: airbnb-base\nenv:\n  jest: true\n\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/.gitignore",
    "content": "node_modules\npackage-lock.json\n.env\ncoverage\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/.gitkeep",
    "content": ""
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/Dockerfile",
    "content": "# Use Node v11.2 as the base image.\nFROM node:11.2.0-alpine\n\n#Set the working directory\nWORKDIR /usr/app\n\n# Copy everything in current directory to /server folder\nADD . /server\n\n# Install dependencies\nRUN cd /server; \\\n    npm install\n\nEXPOSE 3000\n\n# Run node \nCMD [\"node\", \"/server/src/server.js\"]"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/__mocks__/amqp-ts-async.js",
    "content": "/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n\n\nconst bind = jest.fn((exchange) => {\n});\n\nconst activateConsumer = jest.fn((onRecieve) => {\n  onRecieve();\n});\n\nconst send = jest.fn(msg => msg);\n\nconst declareExchange = jest.fn((exchangeName, type, options) => {\n  return {\n    send,\n  };\n});\n\nconst declareQueue = jest.fn((exchangeName, type, options) => {\n  return {\n    bind,\n    activateConsumer,\n  };\n});\n\nconst close = jest.fn();\n\nconst connection = jest.fn((url) => {\n  return {\n    connectionUrl: url,\n    declareExchange,\n    declareQueue,\n    close,\n  };\n});\n\nconst message = jest.fn(msg => msg);\n\nmodule.exports.Connection = connection;\nmodule.exports.activateConsumer = activateConsumer;\nmodule.exports.bind = bind;\nmodule.exports.declareExchange = declareExchange;\nmodule.exports.declareQueue = declareQueue;\nmodule.exports.Message = message;\nmodule.exports.send = send;\nmodule.exports.close = close;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/__mocks__/winston.js",
    "content": "/* eslint-disable no-unused-vars */\n\nmodule.exports.info = jest.fn((message) => {\n});\n\nmodule.exports.error = jest.fn((message) => {\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/package.json",
    "content": "{\n  \"name\": \"user-management\",\n  \"version\": \"1.0.0\",\n  \"description\": \"User Management Service - Reposible for adding, getting, updating new users, their contact details, activity etc.\",\n  \"main\": \"./src/server.js\",\n  \"scripts\": {\n    \"start\": \"node ./src/server.js\",\n    \"test\": \"jest --coverage\",\n    \"watch\": \"jest --coverage --watchAll\",\n    \"lint\": \"eslint ./src && eslint ./tests\",\n    \"testOnly\": \"jest\",\n    \"checkCodeQuality\": \"eslint ./src && eslint ./tests && jest --coverage\"\n  },\n  \"author\": \"Rithin Chalumuri\",\n  \"license\": \"MIT\",\n  \"jest\": {\n    \"testEnvironment\": \"node\",\n    \"verbose\": true,\n    \"coverageThreshold\": {\n      \"global\": {\n        \"branches\": 100,\n        \"functions\": 100,\n        \"lines\": 100,\n        \"statements\": -10\n      }\n    }\n  },\n  \"dependencies\": {\n    \"amqp-ts-async\": \"^1.3.7\",\n    \"dotenv\": \"^6.1.0\",\n    \"koa\": \"^2.6.2\",\n    \"koa-bodyparser\": \"^4.2.1\",\n    \"koa-helmet\": \"^4.0.0\",\n    \"koa-jwt\": \"^3.5.1\",\n    \"koa-logger\": \"^3.2.0\",\n    \"koa-router\": \"^7.4.0\",\n    \"mongoose\": \"^5.3.13\",\n    \"winston\": \"^3.1.0\"\n  },\n  \"devDependencies\": {\n    \"eslint\": \"^5.9.0\",\n    \"eslint-config-airbnb-base\": \"^13.1.0\",\n    \"eslint-plugin-import\": \"^2.14.0\",\n    \"jest\": \"^23.6.0\",\n    \"supertest\": \"^3.3.0\"\n  }\n}\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/app.js",
    "content": "// Import the required npm packages\nconst Koa = require('koa');\nconst Logger = require('koa-logger');\nconst Helmet = require('koa-helmet');\nconst BodyParser = require('koa-bodyparser');\n\n// Get the API routes  file\nconst userRouter = require('./routes/user.routes');\n\n// Init Koa API App\nconst app = new Koa();\napp.use(Logger());\napp.use(BodyParser());\napp.use(Helmet());\n\n// Setup the API routes\napp.use(userRouter.routes()).use(userRouter.allowedMethods({ throw: true }));\n\nmodule.exports = app;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/controllers/__mocks__/user.controller.js",
    "content": "const userController = {};\n\nuserController.find = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = '';\n});\n\nuserController.findById = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\nuserController.add = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = '';\n});\n\nuserController.update = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\nuserController.delete = jest.fn(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = ctx.params.id;\n});\n\nmodule.exports = userController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/controllers/user.controller.js",
    "content": "const Users = require('../models/user.model');\nconst userAddedMessage = require('../message-bus/send/user.added');\n\nconst userController = {\n  find: async (ctx) => {\n    try {\n      const newUser = await Users.create({\n        emailAddress: \"test@gmail.com\"\n      });\n      userAddedMessage.send(ctx.request.body);\n      ctx.body = newUser;\n    } catch (err) {\n      ctx.throw(422);\n    }\n  },\n\n  findById: async (ctx) => {\n    try {\n      const result = await Users.findById(ctx.params.id);\n      if (!result) {\n        ctx.throw(404, 'User Not Found');\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n\n  add: async (ctx) => {\n    try {\n      const newUser = await Users.create(ctx.request.body);\n      userAddedMessage.send(ctx.request.body);\n      ctx.body = newUser;\n    } catch (err) {\n      ctx.throw(422);\n    }\n  },\n\n  update: async (ctx) => {\n    try {\n      const result = await Users.findByIdAndUpdate(\n        ctx.params.id,\n        ctx.request.body,\n      );\n      if (!result) {\n        ctx.throw(404);\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n\n  delete: async (ctx) => {\n    try {\n      const result = await Users.findByIdAndRemove(ctx.params.id);\n      if (!result) {\n        ctx.throw(404);\n      }\n      ctx.body = result;\n    } catch (err) {\n      if (err.name === 'CastError' || err.name === 'NotFoundError') {\n        ctx.throw(404);\n      } else {\n        ctx.throw(500);\n      }\n    }\n  },\n};\n\nmodule.exports = userController;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/environment/config.js",
    "content": "const config = {\n  name: 'User Management Service',\n  baseAPIRoute: 'api',\n  port: process.env.PORT || 8080,\n  messagebus: process.env.MESSAGE_BUS || 'amqp://rabbitmq',\n  environment: process.env.ENVIRONMENT || 'dev',\n  db: {\n    uri: process.env.DB_URI\n  },\n  services: {\n  },\n  messageTimeout: 500,\n  jwtsecret: 'yoursecretkey',\n};\n\nconfig.startedMessage = `${config.name} is running on port ${config.port}/`;\n\nmodule.exports = config;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/message-bus/send/user.added.js",
    "content": "const logger = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../../environment/config');\n\nconst exchangeName = 'user.added';\n\nmodule.exports = {\n  send: (user) => {\n    try {\n      if (!user) {\n        throw new Error('Sould send a valid user to message queue');\n      }\n      console.log('sedning message to MQ')\n      const connection = new amqp.Connection(config.messagebus);\n      const exchange = connection.declareExchange(exchangeName, 'fanout', { durable: false });\n      const message = new amqp.Message(JSON.stringify(user));\n      exchange.send(message);\n      setTimeout(() => {\n        connection.close();\n      }, config.messageTimeout);\n    } catch (err) {\n      logger.error(`Error Sending Article Added Event to ${exchangeName}: ${err}`);\n    }\n  },\n};\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/middlewares/__mocks__/jwt.js",
    "content": "const jwt = jest.fn((ctx, next) => {\n  next();\n});\n\nmodule.exports = jwt;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/middlewares/jwt.js",
    "content": "const koaJwt = require('koa-jwt');\nconst config = require('../environment/config');\n\nmodule.exports = koaJwt({\n  secret: config.jwtsecret,\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/models/__mocks__/user.model.js",
    "content": "/* eslint-disable arrow-body-style */\n\nconst userModel = {};\n\nlet data = [];\n\nuserModel.find = jest.fn(() => data);\n\nuserModel.findById = jest.fn((id) => {\n  return data.find(user => user.id === id);\n});\n\nuserModel.create = jest.fn((user) => {\n  data.push(user);\n  return user;\n});\n\nuserModel.findByIdAndUpdate = jest.fn((id, updateduser) => {\n  const index = data.findIndex(user => user.id === id);\n  if (index >= 0) {\n    data[index] = updateduser;\n  }\n  return updateduser;\n});\n\nuserModel.findByIdAndRemove = jest.fn((id) => {\n  const index = data.findIndex(user => user.id === id);\n  data.splice(index, 1);\n  return id;\n});\n\nuserModel.count = () => data.length;\nuserModel.reset = () => { data = []; };\n\nmodule.exports = userModel;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/models/user.model.js",
    "content": "const mongoose = require('mongoose');\n\nconst UserSchema = new mongoose.Schema({\n  createdDate: { type: Date, default: Date.now },\n  updatedDate: { type: Date, default: Date.now },\n  firstName: { type: String, require: false },\n  lastName: { type: String, require: false },\n  emailAddress: { type: String, require: true },\n  description: { type: String, require: false },\n  meta: {\n    likes: { type: Number, default: 0 },\n  },\n  role: { type: String, require: true, default: 'regular' },\n  imagesUID: [String],\n  tags: [String],\n});\n\nmodule.exports = mongoose.model('User', UserSchema);\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/routes/user.routes.js",
    "content": "const KoaRouter = require('koa-router');\nconst config = require('../environment/config');\nconst usersController = require('../controllers/user.controller');\n\nconst api = 'users';\n\nconst router = new KoaRouter();\n\nrouter.prefix(`/${config.baseAPIRoute}/${api}`);\n\n// GET /api/users\nrouter.get('/', usersController.find);\n\n// POST /api/users\nrouter.post('/', usersController.add);\n\n// GET /api/users/id\nrouter.get('/:id', usersController.findById);\n\n// PUT /api/users/id\nrouter.put('/:id', usersController.update);\n\n// DELETE /api/users/id\nrouter.delete('/:id', usersController.delete);\n\nmodule.exports = router;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/src/server.js",
    "content": "/* eslint-disable no-console */\n\n// Init the environment variables and server configurations\nrequire('dotenv').config();\n\n// Import the required packages\nconst Mongoose = require('mongoose');\nconst config = require('./environment/config');\nconst app = require('./app');\n\n// Init Database Connection\nMongoose.connect('mongodb://mongo/test');\nMongoose.connection.on('error', console.error);\n\n// Run the API Server\napp.listen(config.port, () => {\n  console.log(config.startedMessage);\n  console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');\n  console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')\n\n  console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')\n\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/__snapshots__/user.added.message.send.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Send Should correcly parse the json object 1`] = `mockConstructor {}`;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/__snapshots__/user.controller.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`findById should return user when correct id is passed 1`] = `\nObject {\n  \"emailAddress\": \"test@email.com\",\n  \"firstName\": \"Test User\",\n  \"id\": 123,\n}\n`;\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/app.test.js",
    "content": "/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\n\nconst Koa = require('koa');\nconst userRouter = require('../../src/routes/user.routes');\n\nconst mockUserRoutes = jest.fn(() => { return async (ctx, next) => {}; });\nuserRouter.routes = mockUserRoutes;\n\ndescribe('Koa App', () => {\n  test('Should return valid koa application', () => {\n    const app = require('../../src/app');\n    expect(app).toBeInstanceOf(Koa);\n  });\n\n  test('Should have user routes', () => {\n    require('../../src/app');\n    expect(mockUserRoutes.mock.calls.length).toBe(1);\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/config.test.js",
    "content": "const config = require('../../src/environment/config');\n\ndescribe('config', () => {\n  test('should load default values', () => {\n    expect(config.name).not.toBeNull();\n    expect(config.port).not.toBeNull();\n    expect(config.baseAPIRoute).not.toBeNull();\n    expect(config.environment).not.toBeNull();\n    expect(config.messagebus).not.toBeNull();\n    expect(config.db.uri).not.toBeNull();\n    expect(config.db.username).not.toBeNull();\n    expect(config.db.password).not.toBeNull();\n    expect(config).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/server.test.js",
    "content": "/* eslint-disable global-require */\n\nconst mongoose = require('mongoose');\nconst app = require('../../src/app');\nconst config = require('../../src/environment/config');\n\nconst consoleObj = console;\nconst consoleLogMock = jest.fn();\n\nconst mockConnectDB = jest.fn();\nconst mockListen = jest.fn((port, startedMessage) => {\n  startedMessage();\n});\n\nmongoose.connect = mockConnectDB;\napp.listen = mockListen;\nconsoleObj.log = consoleLogMock;\n\nafterEach(() => {\n  mockListen.mockReset();\n  mockConnectDB.mockReset();\n  consoleLogMock.mockReset();\n});\n\ntest('Server works', async () => {\n  require('../../src/server');\n\n  expect(mockConnectDB.mock.calls.length).toBe(1);\n  expect(mockConnectDB.mock.calls[0][0]).toBe(config.db.uri);\n  expect(mockConnectDB.mock.calls[0][1].user).toBe(config.db.username);\n  expect(mockConnectDB.mock.calls[0][1].pass).toBe(config.db.password);\n\n  expect(mockListen.mock.calls.length).toBe(1);\n  expect(mockListen.mock.calls[0][0]).toBe(config.port);\n  expect(mockListen.mock.calls[0][1]).not.toBeNull();\n\n  expect(consoleLogMock.mock.calls.length).toBe(1);\n  expect(consoleLogMock.mock.calls[0][0]).toBe(config.startedMessage);\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/user.added.message.send.test.js",
    "content": "/* eslint-disable no-unused-vars */\n/* eslint-disable global-require */\njest.mock('winston');\njest.mock('amqp-ts-async');\njest.useFakeTimers();\n\nconst winston = require('winston');\nconst amqp = require('amqp-ts-async');\nconst config = require('../../src/environment/config');\n\nconst message = {\n  title: 'Test Article',\n  description: 'Test Text',\n};\n\ndescribe('Message Broker Connection', () => {\n  afterEach(() => {\n    amqp.close.mockClear();\n    amqp.declareExchange.mockClear();\n    jest.mock('amqp-ts-async');\n  });\n\n  test('Should connect to correct url', () => {\n    require('../../src/message-bus/send/user.added').send(message);\n    expect(amqp.Connection).toBeCalledTimes(1);\n    expect(amqp.Connection).toBeCalledWith(config.messagebus);\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should init with correct exchange details', () => {\n    require('../../src/message-bus/send/user.added').send(message);\n    expect(amqp.declareExchange.mock.calls.length).toBe(1);\n    expect(amqp.declareExchange.mock.calls[0][0]).toBe('user.added');\n    expect(amqp.declareExchange.mock.calls[0][1]).toBe('fanout');\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should close connection after timeout', () => {\n    jest.runAllTimers();\n    require('../../src/message-bus/send/user.added').send(message);\n    expect(amqp.close.mock.calls.length).toBeGreaterThan(0);\n    expect(winston.error).not.toBeCalled();\n  });\n});\n\ndescribe('Send', () => {\n  afterEach(() => {\n    amqp.send.mockClear();\n    jest.mock('amqp-ts-async');\n  });\n\n  test('Should send succesfully when valid user is passed', () => {\n    require('../../src/message-bus/send/user.added').send(message);\n    expect(amqp.send).toHaveBeenCalled();\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should correcly parse the json object', () => {\n    require('../../src/message-bus/send/user.added').send(message);\n    expect(amqp.send).toBeCalledTimes(1);\n    expect(amqp.Message).toBeCalledWith(JSON.stringify(message));\n    expect(amqp.send.mock.calls[0][0]).toMatchSnapshot();\n    expect(winston.error).not.toBeCalled();\n  });\n\n  test('Should log exception if there null user is passed', () => {\n    require('../../src/message-bus/send/user.added').send(null);\n    expect(amqp.send).not.toBeCalled();\n    expect(winston.error).toBeCalled();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/user.controller.test.js",
    "content": "// #region Disabled ESLint Rules...\n\n/* eslint-disable arrow-body-style */\n/* eslint-disable no-unused-vars */\n\n// #endregion\n\n// #region Setup Mocks...\n\njest.mock('../../src/models/user.model');\n\n// #endregion\n\n// #region Imports...\n\nconst userModel = require('../../src/models/user.model');\nconst userController = require('../../src/controllers/user.controller');\n\n// #endregion\n\n// #region Methods...\nconst sampleUser = {\n  id: 123,\n  emailAddress: 'test@email.com',\n  firstName: 'Test User',\n};\n\nconst createMockContext = (context = {}) => {\n  const ctx = context;\n  ctx.throw = jest.fn((errorCode) => {});\n  return ctx;\n};\n\n// #endregion\n\n// #region Unit Tests...\n\n// #region userController_add\n\ndescribe('add', async () => {\n  const createMockOriginalImplementation = userModel.create;\n\n  beforeEach(() => {\n    userModel.create.mockClear();\n  });\n\n  afterEach(() => {\n    userModel.reset();\n    userModel.create = createMockOriginalImplementation;\n  });\n\n  test('should add user when valid data is passed', async () => {\n    const ctx = createMockContext({ request: { body: sampleUser } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(sampleUser);\n    expect(ctx.body).toMatchObject(sampleUser);\n    expect(ctx.throw).not.toBeCalled();\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should add user successfully with multiple tags', async () => {\n    const newsampleUser = Object.assign({}, sampleUser);\n    newsampleUser.tags = ['Sample', 'user'];\n\n    const ctx = createMockContext({ request: { body: newsampleUser } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(newsampleUser);\n    expect(ctx.body).toMatchObject(newsampleUser);\n    expect(ctx.throw).not.toBeCalled();\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should add user successfully without images', async () => {\n    const ctx = createMockContext({ request: { body: sampleUser } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(sampleUser);\n    expect(ctx.body).toMatchObject(sampleUser);\n    expect(ctx.throw).not.toBeCalled();\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should add user successfully with images', async () => {\n    const newsampleUser = Object.assign({}, sampleUser);\n    newsampleUser.images = ['imageLink1', 'imageLink2'];\n\n    const ctx = createMockContext({ request: { body: newsampleUser } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(newsampleUser);\n    expect(ctx.body).toMatchObject(newsampleUser);\n    expect(ctx.throw).not.toBeCalled();\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should throw an error and not add user when invalid data is passed', async () => {\n    userModel.create = jest.fn((user) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(userModel.count()).toBe(0);\n  });\n\n  test('should throw an error and not add user when email is missing', async () => {\n    userModel.create = jest.fn((user) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(userModel.count()).toBe(0);\n  });\n\n  test('should throw an error and not add user when role is missing', async () => {\n    userModel.create = jest.fn((user) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ request: { body: null } });\n\n    await userController.add(ctx);\n\n    expect(userModel.create).toBeCalledTimes(1);\n    expect(userModel.create).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(422);\n    expect(userModel.count()).toBe(0);\n  });\n});\n\n// #endregion\n\n// #region userController_delete\ndescribe('delete', async () => {\n  const deleteOriginalMockImplementation = userModel.findByIdAndRemove;\n\n  beforeEach(() => {\n    userModel.create(sampleUser);\n    userModel.findByIdAndRemove.mockClear();\n  });\n\n  afterEach(() => {\n    userModel.reset();\n    userModel.findByIdAndRemove = deleteOriginalMockImplementation;\n  });\n\n  test('should delete user successfully when correct id is passed', async () => {\n    const ctx = createMockContext({ params: { id: sampleUser.id } });\n    const beforeCount = userModel.count();\n\n    await userController.delete(ctx);\n\n    expect(userModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(userModel.findByIdAndRemove).toBeCalledWith(sampleUser.id);\n    expect(ctx.body).toBe(sampleUser.id);\n    expect(ctx.throw).not.toBeCalled();\n    expect(userModel.count()).toBe(beforeCount - 1);\n  });\n\n  test('should throw an error when user to delete not found', async () => {\n    userModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await userController.delete(ctx);\n\n    expect(userModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(userModel.findByIdAndRemove).toBeCalledWith(555);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when user id passed is null', async () => {\n    userModel.findByIdAndRemove = jest.fn((id) => {\n      return null;\n    });\n\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await userController.delete(ctx);\n\n    expect(userModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(userModel.findByIdAndRemove).toBeCalledWith(555);\n    expect(ctx.body).toBeNull();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when id passed is of incorrect type', async () => {\n    userModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'CastError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 0.9 } });\n\n    await userController.delete(ctx);\n\n    expect(userModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(userModel.findByIdAndRemove).toBeCalledWith(0.9);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw a 500 error and return null for any other errors caught', async () => {\n    userModel.findByIdAndRemove = jest.fn((id) => {\n      const error = new Error();\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 123 } });\n\n    await userController.delete(ctx);\n\n    expect(userModel.findByIdAndRemove).toBeCalledTimes(1);\n    expect(userModel.findByIdAndRemove).toBeCalledWith(123);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n  });\n});\n// #endregion\n\n// #region userController_find\n\ndescribe('find', async () => {\n  afterEach(() => {\n    userModel.find.mockClear();\n    userModel.reset();\n  });\n\n  test('should return empty list when no data present', async () => {\n    const ctx = createMockContext();\n    await userController.find(ctx);\n\n    expect(ctx.body).toMatchObject([]);\n    expect(userModel.find).toBeCalledTimes(1);\n  });\n\n  test('should return values when data present', async () => {\n    userModel.create(sampleUser);\n\n    const ctx = createMockContext();\n    await userController.find(ctx);\n\n    expect(userModel.find).toBeCalledTimes(1);\n    expect(ctx.body).toMatchObject([sampleUser]);\n  });\n});\n\n// #endregion\n\n// #region userController_findById\n\ndescribe('findById', async () => {\n  const findByIdOrignialMockImplementation = userModel.findById;\n\n  beforeEach(() => {\n    userModel.create(sampleUser);\n    userModel.findById.mockClear();\n  });\n\n  afterEach(() => {\n    userModel.reset();\n    userModel.findById = findByIdOrignialMockImplementation;\n  });\n\n  test('should return user when correct id is passed', async () => {\n    const ctx = createMockContext({ params: { id: sampleUser.id } });\n\n    await userController.findById(ctx);\n\n    expect(userModel.findById).toBeCalledTimes(1);\n    expect(userModel.findById).toBeCalledWith(sampleUser.id);\n    expect(ctx.body).toMatchSnapshot();\n    expect(ctx.throw).not.toBeCalled();\n  });\n\n  test('should throw an error when id passed doesn\\'t exist', async () => {\n    const ctx = createMockContext({ params: { id: 555 } });\n\n    await userController.findById(ctx);\n\n    expect(userModel.findById).toBeCalledTimes(1);\n    expect(userModel.findById).toBeCalledWith(555);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404, 'User Not Found');\n  });\n\n  test('should throw an error when id passed is null', async () => {\n    userModel.findById = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: null } });\n\n    await userController.findById(ctx);\n\n    expect(userModel.findById).toBeCalledTimes(1);\n    expect(userModel.findById).toBeCalledWith(null);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw an error when id passed is of incorrect type', async () => {\n    userModel.findById = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'CastError';\n      throw error;\n    });\n\n    const ctx = createMockContext({ params: { id: 0.99 } });\n\n    await userController.findById(ctx);\n\n    expect(userModel.findById).toBeCalledTimes(1);\n    expect(userModel.findById).toBeCalledWith(0.99);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n  });\n\n  test('should throw a 500 error and return null for any other errors caught', async () => {\n    userModel.findById = jest.fn((id) => {\n      throw new Error();\n    });\n\n    const ctx = createMockContext({ params: { id: 123 } });\n\n    await userController.findById(ctx);\n\n    expect(userModel.findById).toBeCalledTimes(1);\n    expect(userModel.findById).toBeCalledWith(123);\n    expect(ctx.body).toBeUndefined();\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n  });\n});\n\n// #endregion\n\n// #region userController_update\ndescribe('update', async () => {\n  const updateOriginalMockImplemenation = userModel.findByIdAndUpdate;\n\n  beforeEach(() => {\n    userModel.findByIdAndUpdate.mockClear();\n    userModel.create(sampleUser);\n  });\n\n  afterEach(() => {\n    userModel.reset();\n    userModel.findByIdAndUpdate = updateOriginalMockImplemenation;\n  });\n\n  test('should update user correctly when valid id and data are passed', async () => {\n    const newsampleUser = Object.assign({}, sampleUser);\n    newsampleUser.firstName = 'firstName Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: sampleUser.id },\n        request: { body: newsampleUser },\n      },\n    );\n\n    await userController.update(ctx);\n\n    expect(userModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(userModel.findByIdAndUpdate).toBeCalledWith(sampleUser.id, newsampleUser);\n    expect(userModel.findById(sampleUser.id).firstName).toBe(newsampleUser.firstName);\n    expect(ctx.throw).not.toBeCalled();\n    expect(ctx.body).toBe(newsampleUser);\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should throw an error when user not found', async () => {\n    userModel.findByIdAndUpdate = jest.fn((id) => {\n      const error = new Error();\n      error.name = 'NotFoundError';\n      throw error;\n    });\n\n    const newsampleUser = Object.assign({}, sampleUser);\n    newsampleUser.firstName = 'firstName Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 1234 },\n        request: { body: newsampleUser },\n      },\n    );\n\n    await userController.update(ctx);\n\n    expect(userModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(userModel.findByIdAndUpdate).toBeCalledWith(1234, newsampleUser);\n    expect(userModel.findById(sampleUser.id)).toBe(sampleUser);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n    expect(ctx.body).toBeUndefined();\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should throw an error when model returns null', async () => {\n    userModel.findByIdAndUpdate = jest.fn((id) => {\n      return null;\n    });\n\n    const newsampleUser = Object.assign({}, sampleUser);\n    newsampleUser.firstName = 'firstName Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 123 },\n        request: { body: newsampleUser },\n      },\n    );\n\n    await userController.update(ctx);\n\n    expect(userModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(userModel.findByIdAndUpdate).toBeCalledWith(123, newsampleUser);\n    expect(userModel.findById(sampleUser.id)).toBe(sampleUser);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(404);\n    expect(ctx.body).toBeNull();\n    expect(userModel.count()).toBe(1);\n  });\n\n  test('should throw an error 500 for any other issues found', async () => {\n    userModel.findByIdAndUpdate = jest.fn((id) => {\n      const error = new Error();\n      throw error;\n    });\n\n    const newsampleUser = Object.assign({}, sampleUser);\n    newsampleUser.firstName = 'firstName Changed!';\n\n    const ctx = createMockContext(\n      {\n        params: { id: 1234 },\n        request: { body: newsampleUser },\n      },\n    );\n\n    await userController.update(ctx);\n\n    expect(userModel.findByIdAndUpdate).toBeCalledTimes(1);\n    expect(userModel.findByIdAndUpdate).toBeCalledWith(1234, newsampleUser);\n    expect(userModel.findById(sampleUser.id)).toBe(sampleUser);\n    expect(ctx.throw).toBeCalledTimes(1);\n    expect(ctx.throw).toBeCalledWith(500);\n    expect(ctx.body).toBeUndefined();\n    expect(userModel.count()).toBe(1);\n  });\n});\n// #endregion\n\n// #endregion\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/user.model.test.js",
    "content": "/* eslint-disable global-require */\nconst mongoose = require('mongoose');\n\nconst mockSchema = jest.fn();\nconst mockModel = jest.fn((modelName, schema) => ({ modelName, schema }));\n\nmongoose.model = mockModel;\nmongoose.Schema = mockSchema;\n\ndescribe('User Model', () => {\n  test('Should have the correct user model name', () => {\n    const model = require('../../src/models/user.model');\n    expect(model.modelName).toBe('User');\n  });\n\n  test('Schema should contain the required fields', () => {\n    require('../../src/models/user.model');\n    expect(mockSchema).toBeCalledTimes(1);\n    const schema = mockSchema.mock.calls[0][0];\n    expect(Object.keys(schema).length).toBe(10);\n    expect(schema.createdDate).toBeDefined();\n    expect(schema.updatedDate).toBeDefined();\n    expect(schema.firstName).toBeDefined();\n    expect(schema.description).toBeDefined();\n    expect(schema.lastName).toBeDefined();\n    expect(schema.meta).toBeDefined();\n    expect(schema.emailAddress).toBeDefined();\n    expect(schema.imagesUID).toBeDefined();\n    expect(schema.tags).toBeDefined();\n    expect(schema.role).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "event-driven-microservices-docker/services/user-management/tests/unit/user.routes.test.js",
    "content": "jest.mock('../../src/controllers/user.controller');\njest.mock('../../src/middlewares/jwt');\n\nconst request = require('supertest');\nconst Koa = require('koa');\nconst userRoutes = require('../../src/routes/user.routes');\nconst userController = require('../../src/controllers/user.controller');\n\nconst app = new Koa().use(userRoutes.routes());\n\ndescribe('GET /api/users', () => {\n  test('Should sucessfully get status 200', async () => {\n    const response = await request(app.callback()).get('/api/users');\n\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('');\n    expect(userController.find).toBeCalledTimes(1);\n  });\n});\n\ndescribe('GET /api/users/:id', () => {\n  test('Should sucessfully get status 200', async () => {\n    const response = await request(app.callback()).get('/api/users/123');\n\n    expect(userController.findById).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n  });\n});\n\ndescribe('POST /api/users', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).post('/api/users');\n\n    expect(userController.add).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('');\n    done();\n  });\n});\n\ndescribe('PUT /api/users/:id', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).put('/api/users/123');\n\n    expect(userController.update).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n    done();\n  });\n});\n\ndescribe('DELETE /api/users/:id', () => {\n  test('Should sucessfully get status 200', async (done) => {\n    const response = await request(app.callback()).delete('/api/users/123');\n\n    expect(userController.delete).toBeCalledTimes(1);\n    expect(response.status).toBe(200);\n    expect(response.text).toEqual('123');\n    done();\n  });\n});\n"
  },
  {
    "path": "node js-with-serverless/.gitignore",
    "content": "node_modules/\n.DS_Store\nnpm-debug.log\ndist/\ncoverage/\nmongo/db\n"
  },
  {
    "path": "node js-with-serverless/README.md",
    "content": "# Serverless-Typescript-CRUD-DYNAMODB\nCRUD operations using serverless typescript plugin with node js 12.XX \n"
  },
  {
    "path": "node js-with-serverless/functions/delete_item.ts",
    "content": "import { DynamoDB } from 'aws-sdk';\n\nconst documentClient = new DynamoDB.DocumentClient({\n    region: process.env.REGION\n});\n\nexport const deleteItem = async (event) => {\n\n    try {\n        const { pathParameters: { id } } = event;\n        const params = {\n            TableName: process.env.TABLE_NAME,\n            Key: { id }\n        };\n        await documentClient.delete(params).promise();\n        const response = {\n            statusCode: 200,\n            body: JSON.stringify(\n                {\n                    message: 'success deleted !'\n                },\n                null,\n                2\n            )\n        }\n        return response;\n    } catch (e) {\n        return {\n            statusCode: 500,\n            body: JSON.stringify(e)\n        };\n    }\n\n\n}"
  },
  {
    "path": "node js-with-serverless/functions/edit_item.ts",
    "content": "import {DynamoDB} from 'aws-sdk';\nimport { eventData, dbItem } from '../models/table_schema';\nimport { dynamoUpdatedParams } from '../shared/update_dynamo';\n\nconst documentClient = new DynamoDB.DocumentClient({\n    region:process.env.REGION\n});\n\nexport const editItem = async(event)=> {\n  try {\n    const {pathParameters: { id } } = event;\n    const eventItem:eventData =JSON.parse(event.body) \n    const dbUpdateItem:dbItem = dynamoUpdatedParams(eventItem,id);\n    await documentClient.put(dbUpdateItem).promise();\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(\n        {\n          message: 'success updated !'\n        })\n    };\n    return response;\n  } catch (e) {\n    return {\n      statusCode: 500,\n      body: JSON.stringify(e)\n    };\n  }\n\n\n  }"
  },
  {
    "path": "node js-with-serverless/functions/read_all.ts",
    "content": "import {DynamoDB} from 'aws-sdk';\n\nconst documentClient = new DynamoDB.DocumentClient({\n    region:process.env.REGION\n});\n\nexport const readAll = async(event)=> {\n  const params = {\n    TableName: process.env.TABLE_NAME\n  };\n  try {\n    const data = await documentClient.scan(params).promise();\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(data.Items)\n    };\n    return response;\n  } catch (e) {\n    return {\n      statusCode: 500,\n      body: JSON.stringify(e)\n    };\n  }\n\n\n  }"
  },
  {
    "path": "node js-with-serverless/functions/read_single_item.ts",
    "content": "import {DynamoDB} from 'aws-sdk';\n\nconst documentClient = new DynamoDB.DocumentClient({\n    region:process.env.REGION\n});\n\nexport const readSingleItem = async(event)=> {\n  const {pathParameters: { id } } = event;\n  const params = {\n    TableName: process.env.TABLE_NAME,\n    Key: {id}\n  };\n  try {\n    const data = await documentClient.get(params).promise();\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(data.Item? data.Item:{message:'Item not found'})\n    };\n    return response;\n  } catch (e) {\n    return {\n      statusCode: 500,\n      body: JSON.stringify(e)\n    };\n  }\n\n\n  }"
  },
  {
    "path": "node js-with-serverless/functions/write_item.ts",
    "content": "import {DynamoDB} from 'aws-sdk';\nimport { eventData, dbItem } from '../models/table_schema';\nimport { dynamoParams } from '../shared/create_dynamo';\n\nconst documentClient = new DynamoDB.DocumentClient({\n    region:process.env.REGION\n});\n\nexport const writeItem = async(event)=> {\ntry{\n    const insertData:eventData =JSON.parse(event.body) \n    const dbInsertItem:dbItem = dynamoParams(insertData);\n    await documentClient.put(dbInsertItem).promise();\n    const response = {\n        statusCode: 200,\n        body: JSON.stringify(\n          {\n            message: 'success inserted !'\n          },\n          null,\n          2\n        )\n    }\n    return response;\n}catch (e) {\n    return {\n      statusCode: 500,\n      body: JSON.stringify(e)\n    };\n  }\n  }"
  },
  {
    "path": "node js-with-serverless/models/table_schema.ts",
    "content": "export interface eventData {\n    title: string,\n    description:string,\n    compl_time:string,\n    creat_time:string\n}\n\nexport interface schema extends eventData{\n      id:string\n}\n\nexport interface dbItem {\n    TableName:string,\n    Item:schema\n}"
  },
  {
    "path": "node js-with-serverless/package.json",
    "content": "{\n  \"name\": \"xanalytics-android-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"gully\": \"rm -rf .build && sls invoke local -f $1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"aws-sdk\": \"^2.617.0\",\n    \"serverless-offline\": \"^5.12.1\",\n    \"serverless-plugin-typescript\": \"^1.1.9\",\n    \"typescript\": \"^3.7.5\",\n    \"@types/node\": \"^13.7.1\"\n  },\n  \"dependencies\": {\n    \n  }\n}\n"
  },
  {
    "path": "node js-with-serverless/serverless.yml",
    "content": "service: xanalytics-android-server\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: dev\n  region: us-east-2\n  iamManagedPolicies:\n    - arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess\n  environment:\n    TABLE_NAME: 'android-demo-crud'\n    REGION: ${opt:region, self:provider.region}\n\npackage:\n  exclude:\n    - .build/**\n    - '*/**'\n  individually: true\nfunctions:\n  readAll:\n    handler: functions/read_all.readAll\n    package:\n      include:\n        - functions/read_all.js\n    events:\n      - http:\n          path: todo\n          method: get\n  readSingle:\n    handler: functions/read_single_item.readSingleItem\n    package:\n      include:\n        - functions/read_single_item.js\n    events:\n      - http:\n          path: todo/{id}\n          method: get\n  update:\n    handler: functions/edit_item.editItem\n    package:\n      include:\n        - functions/edit_item.js\n        - models/table_schema.js\n        - shared/update_dynamo.ts\n    events:\n      - http:\n          path: todo/{id}\n          method: put\n  insert:\n    handler: functions/write_item.writeItem\n    package:\n      include:\n        - functions/write_item.js\n        - models/table_schema.js\n        - shared/create_dynamo.js\n    events:\n      - http:\n          path: todo\n          method: post\n  delete:\n    handler: functions/delete_item.deleteItem\n    package:\n      include:\n        - functions/delete_item.js\n    events:\n      - http:\n          path: todo/{id}\n          method: delete\nplugins:\n  - serverless-offline\n  - serverless-plugin-typescript"
  },
  {
    "path": "node js-with-serverless/shared/create_dynamo.ts",
    "content": "import {eventData, dbItem, schema} from '../models/table_schema'\nimport {randomBytes} from 'crypto';\n\nexport const dynamoParams= (Item:eventData)=>{\nconst UUID = randomBytes(16).toString(\"hex\");\nconst item:schema={id:UUID,...Item}\nconst dynamoTableItem:dbItem = {\n        TableName:process.env.TABLE_NAME,\n        Item:item\n}\nreturn dynamoTableItem;\n}"
  },
  {
    "path": "node js-with-serverless/shared/update_dynamo.ts",
    "content": "import {eventData, dbItem, schema} from '../models/table_schema'\n\nexport const dynamoUpdatedParams= (Item:eventData, id:string)=>{\nconst item:schema={id:id,...Item}\nconst dynamoTableItem:dbItem = {\n        TableName:process.env.TABLE_NAME,\n        Item:item\n}\nreturn dynamoTableItem;\n}"
  },
  {
    "path": "node-js-lambda-sqs-serverless/.gitignore",
    "content": "node_modules/\n.DS_Store\nnpm-debug.log\ndist/\ncoverage/\nmongo/db\n"
  },
  {
    "path": "node-js-lambda-sqs-serverless/README.md",
    "content": "# AWSLambdaSQSNode\nAWS Lambda PoC over SQS using Node.js and MongoDB Atlas\n"
  },
  {
    "path": "node-js-lambda-sqs-serverless/data.json",
    "content": "{\n    \"title\": \"ShishQueue\",\n    \"description\": \"Shish REST API with Queue\"\n}"
  },
  {
    "path": "node-js-lambda-sqs-serverless/db.js",
    "content": "const mongoose = require('mongoose');\nmongoose.Promise = global.Promise;\nlet isConnected;\n\nconst options = {\n    autoIndex: false, // Don't build indexes\n    reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect\n    reconnectInterval: 500, // Reconnect every 500ms\n    poolSize: 10, // Maintain up to 10 socket connections\n    // If not connected, return errors immediately rather than waiting for reconnect\n    bufferMaxEntries: 0\n};\n\n\n/* var MongoClient = require('mongodb').MongoClient;\n\nvar uri = process.env.DB; */\n\n\nmodule.exports = connectToDatabase = () => {\n    if (isConnected) {\n        console.log('=> using existing database connection');\n        return Promise.resolve();\n    }\n\n    /* MongoClient.connect(uri, function(err, db) {\n        isConnected = true;\n        console.log(\"connected\");\n        if (err) {\n            console.log(\"Error: \" + err);\n        }\n        //db.close();\n    }); */\n    return mongoose.connect(process.env.DB, options)\n        .then(db => {\n                console.log(\"opening db\");\n                isConnected = db.connections[0].readyState;\n                console.log(\"opened db\");\n            },\n            err => { console.log(\"ERRORRRRRRR: \" + err); }\n        );\n};"
  },
  {
    "path": "node-js-lambda-sqs-serverless/handler.js",
    "content": "require('dotenv').config({ path: './variables.env' });\nvar sqsClient = require('./sqs');\n\nconst connectToDatabase = require('./db');\nconst Note = require('./models/note');\n\nmodule.exports.addtodb = (event, context, callback) => {\n    context.callbackWaitsForEmptyEventLoop = false;\n\n    sqsClient.AWSSQSClient.receiveMessage(function(err, data) {\n        console.log(data.Messages[0].Body);\n        event.body = data.Messages[0].Body;\n    });\n\n    connectToDatabase()\n        .then(() => {\n            Note.create(JSON.parse(event.body))\n                .then(note => callback(null, {\n                    statusCode: 200,\n                    body: JSON.stringify(note)\n                }))\n                .catch(err => callback(null, {\n                    statusCode: err.statusCode || 500,\n                    headers: { 'Content-Type': 'text/plain' },\n                    body: 'Could not create the note.'\n                }));\n        });\n};\n\nmodule.exports.create = (event, context, callback) => {\n    context.callbackWaitsForEmptyEventLoop = false;\n\n    sqsClient.AWSSQSClient.sendMessage(event, function(err, data) {\n        if (err) {\n            console.log(\"Error adding in the Queue: \", err);\n            callback(null, {\n                statusCode: err.statusCode || 500,\n                headers: { 'Content-Type': 'text/plain' },\n                body: 'Could not add to the queue'\n            });\n        } else {\n            console.log(\"Success adding in the Queue: \", data.MessageId);\n            callback(null, {\n                statusCode: 200,\n                body: JSON.stringify(data)\n            });\n        }\n    });\n};\n\nmodule.exports.getOne = (event, context, callback) => {\n    context.callbackWaitsForEmptyEventLoop = false;\n\n    connectToDatabase()\n        .then(() => {\n            Note.findById(event.pathParameters.id)\n                .then(note => callback(null, {\n                    statusCode: 200,\n                    body: JSON.stringify(note)\n                }))\n                .catch(err => callback(null, {\n                    statusCode: err.statusCode || 500,\n                    headers: { 'Content-Type': 'text/plain' },\n                    body: 'Could not fetch the note.'\n                }));\n        });\n};\n\nmodule.exports.getAll = (event, context, callback) => {\n    context.callbackWaitsForEmptyEventLoop = false;\n    console.log(\"1\");\n    connectToDatabase()\n        .then(() => {\n            Note.find()\n                .then(notes => callback(null, {\n                    statusCode: 200,\n                    body: JSON.stringify(notes)\n                }))\n                .catch(err => callback(null, {\n                    statusCode: err.statusCode || 500,\n                    headers: { 'Content-Type': 'text/plain' },\n                    body: 'Could not fetch the notes.'\n                }))\n        });\n};\n\nmodule.exports.update = (event, context, callback) => {\n    context.callbackWaitsForEmptyEventLoop = false;\n\n    connectToDatabase()\n        .then(() => {\n            Note.findByIdAndUpdate(event.pathParameters.id, JSON.parse(event.body), { new: true })\n                .then(note => callback(null, {\n                    statusCode: 200,\n                    body: JSON.stringify(note)\n                }))\n                .catch(err => callback(null, {\n                    statusCode: err.statusCode || 500,\n                    headers: { 'Content-Type': 'text/plain' },\n                    body: 'Could not fetch the notes.'\n                }));\n        });\n};\n\nmodule.exports.delete = (event, context, callback) => {\n    context.callbackWaitsForEmptyEventLoop = false;\n\n    connectToDatabase()\n        .then(() => {\n            Note.findByIdAndRemove(event.pathParameters.id)\n                .then(note => callback(null, {\n                    statusCode: 200,\n                    body: JSON.stringify({ message: 'Removed note with id: ' + note._id, note: note })\n                }))\n                .catch(err => callback(null, {\n                    statusCode: err.statusCode || 500,\n                    headers: { 'Content-Type': 'text/plain' },\n                    body: 'Could not fetch the notes.'\n                }));\n        });\n};"
  },
  {
    "path": "node-js-lambda-sqs-serverless/models/note.js",
    "content": "const mongoose = require('mongoose');\nconst NoteSchema = new mongoose.Schema({\n    title: String,\n    description: String\n});\nmodule.exports = mongoose.model('Note', NoteSchema);"
  },
  {
    "path": "node-js-lambda-sqs-serverless/package.json",
    "content": "{\n  \"name\": \"rest-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"serverless-offline\": \"^3.20.1\"\n  },\n  \"dependencies\": {\n    \"aws-sdk\": \"^2.222.1\",\n    \"dotenv\": \"^5.0.1\",\n    \"mongoose\": \"^5.0.13\"\n  }\n}\n"
  },
  {
    "path": "node-js-lambda-sqs-serverless/serverless.yml",
    "content": "service: rest-api\n\nprovider:\n  name: aws\n  runtime: nodejs6.10 # set node.js runtime\n  memorySize: 128 # set the maximum memory of the Lambdas in Megabytes\n  timeout: 10 # the timeout is 10 seconds (default is 6 seconds)\n  stage: dev # setting the env stage to dev, this will be visible in the routes\n  region: us-east-1\n\nfunctions: # add 5 functions for CRUD\n  addtodb:\n    handler: handler.addtodb # point to exported addtodb function in handler.js\n    events:\n      - http:\n          path: notestodb # path will be domain.name.com/dev/notestodb\n          method: get\n          cors: true\n  create:\n    handler: handler.create # point to exported create function in handler.js\n    events:\n      - http:\n          path: notes # path will be domain.name.com/dev/notes\n          method: post\n          cors: true\n  getOne:\n    handler: handler.getOne\n    events:\n      - http:\n          path: notes/{id} # path will be domain.name.com/dev/notes/1\n          method: get\n          cors: true\n  getAll:\n    handler: handler.getAll # path will be domain.name.com/dev/notes\n    events:\n     - http:\n         path: notes\n         method: get\n         cors: true\n  update:\n    handler: handler.update # path will be domain.name.com/dev/notes/1\n    events:\n     - http:\n         path: notes/{id}\n         method: put\n         cors: true\n  delete:\n    handler: handler.delete\n    events:\n     - http:\n         path: notes/{id} # path will be domain.name.com/dev/notes/1\n         method: delete\n         cors: true\n\nplugins:\n- serverless-offline # adding the plugin to be able to run the offline emulation"
  },
  {
    "path": "node-js-lambda-sqs-serverless/sqs.js",
    "content": "var aws = require('aws-sdk');\naws.config.loadFromPath(__dirname + '/aws-config.json');\nvar sqs = new aws.SQS();\n\n\nmodule.exports.AWSSQSClient = {\n    receiveMessage: function(callback) {\n        var params = {\n            QueueUrl: process.env.SQSURL,\n            VisibilityTimeout: 60\n        };\n\n        sqs.receiveMessage(params, function(err, data) {\n            if (err) {\n                callback(err);\n            } else {\n                callback(null, data);\n            }\n        });\n    },\n\n    sendMessage: function(event, callback) {\n        var params = {\n            MessageBody: event.body,\n            QueueUrl: process.env.SQSURL\n        };\n\n        sqs.sendMessage(params, function(err, data) {\n            if (err) {\n                callback(err);\n            } else {\n                console.log(\"Success adding in the Queue: \", data.MessageId);\n                callback(null, data);\n            }\n        });\n    }\n}"
  },
  {
    "path": "node-microservice-starter/.dockerignore",
    "content": ".git\n.gitignore\nREADME.md\ndocker-compose.yml\nnode_modules\n"
  },
  {
    "path": "node-microservice-starter/.editorconfig",
    "content": "# EditorConfig is awesome: http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n# 2 space indentation\n[**.*]\nindent_style = space\nindent_size = 2\n\n[*.yml]\nindent_style = space\nindent_size = 4\n"
  },
  {
    "path": "node-microservice-starter/.gitattributes",
    "content": "* text=auto\n"
  },
  {
    "path": "node-microservice-starter/.gitignore",
    "content": "node_modules/\n.DS_Store\nnpm-debug.log\ndist/\ncoverage/\nmongo/db\n"
  },
  {
    "path": "node-microservice-starter/README.md",
    "content": "# node-microservice-demo\n[![Code Climate](https://codeclimate.com/github/swimlane/node-microservice-demo/badges/gpa.svg)](https://codeclimate.com/github/swimlane/node-microservice-demo)\n[![Test Coverage](https://codeclimate.com/github/swimlane/node-microservice-demo/badges/coverage.svg)](https://codeclimate.com/github/swimlane/node-microservice-demo/coverage)\n[![Build Status](https://travis-ci.org/swimlane/node-microservice-demo.svg?branch=master)](https://travis-ci.org/swimlane/node-microservice-demo)\n[![codecov](https://codecov.io/gh/swimlane/node-microservice-demo/branch/master/graph/badge.svg)](https://codecov.io/gh/swimlane/node-microservice-demo)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/bbf1a748327f47babd50cdeb86587353)](https://www.codacy.com/app/Swimlane/node-microservice-demo?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=swimlane/node-microservice-demo&amp;utm_campaign=Badge_Grade)\n\nExample project for:\n\n- Micro-service APIs\n- Docker & Docker Compose\n- NGINX\n- Node 6.x\n- TypeScript 2.0\n- Express 4.0\n- Socket.io Websockets\n- PassportJS Auth\n- Swagger 2.0\n- Neo4j\n- MongoDB\n\n\n## Getting Started\n### Pre-reqs\n- [Docker](https://docs.docker.com/engine/installation/)\n- [Docker Compose](https://docs.docker.com/compose/)\n\n### Running\nInstall and start docker by `docker-compose up`.\n\n## Reads\n- [Netflix Scaling Node](https://medium.com/@nodejs/netflixandchill-how-netflix-scales-with-node-js-and-containers-cf63c0b92e57#.9bzn8wm4u)\n- [Building Microservices with OpenSource Technologies](http://www.developer.com/open/building-microservices-with-open-source-technologies.html)\n- [Docker Micro-services with Node](http://anandmanisankar.com/posts/docker-container-nginx-node-redis-example/)\n"
  },
  {
    "path": "node-microservice-starter/docker-compose.yml",
    "content": "version: '2'\n\nservices:\n    mongo:\n        container_name: ms_mongo\n        image: mongo:latest\n        ports:\n            - \"27017:27017\"\n        volumes:\n            - \"./mongo/db:/data/db\"\n\n    nginx:\n        build: ./nginx\n        container_name: ms_nginx\n        links:\n            - store\n            - users\n        ports:\n            - \"80:80\"\n\n    store:\n        build: ./store\n        container_name: ms_store\n        environment:\n            - loglevel=none\n        links:\n            - \"mongo:mongo\"\n        volumes:\n            - \"./store:/src/app\"\n        working_dir: \"/src/app\"\n        ports:\n            - \"8080:8080\"\n            - \"5858:5858\"\n        # command: npm run start\n        command: npm run start\n\n    users:\n        build: ./users\n        container_name: ms_users\n        links:\n            - neo4j\n        volumes:\n            - \"./users:/src/app\"\n        working_dir: \"/src/app\"\n        command: npm start\n"
  },
  {
    "path": "node-microservice-starter/nginx/Dockerfile",
    "content": "# Set nginx base image\nFROM nginx\n\n# File Author / Maintainer\nMAINTAINER Swimlane\n\n# Copy custom configuration file from the current directory\nCOPY nginx.conf /etc/nginx/nginx.conf\n"
  },
  {
    "path": "node-microservice-starter/nginx/nginx.conf",
    "content": "worker_processes 4;\n\nevents { worker_connections 1024; }\n\nhttp {\n\n\tserver {\n\t      listen 80;\n          charset utf-8;\n\n\t      location / {\n\t\t    proxy_pass http://store:8080;\n\t        proxy_http_version 1.1;\n\t        proxy_set_header Upgrade $http_upgrade;\n\t        proxy_set_header Connection 'upgrade';\n\t        proxy_set_header Host $host;\n\t        proxy_cache_bypass $http_upgrade;\n\t      }\n\n\t\t  location ~ ^/users {\n\t\t    rewrite ^/users/(.*) /$1 break;\n\t        proxy_pass http://users:8080;\n\t        proxy_http_version 1.1;\n\t        proxy_set_header Upgrade $http_upgrade;\n\t        proxy_set_header Connection 'upgrade';\n\t        proxy_set_header Host $host;\n\t        proxy_cache_bypass $http_upgrade;\n\t      }\n\t}\n}\n"
  },
  {
    "path": "node-microservice-starter/users/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/eslint-recommended',\n    'plugin:@typescript-eslint/recommended',\n    'prettier',\n    'prettier/@typescript-eslint',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "node-microservice-starter/users/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "node-microservice-starter/users/Dockerfile",
    "content": "FROM node:latest\n\nRUN npm i -g nodemon node-inspector npm-run-all rimraf\n\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\n\nCOPY package.json /usr/src/app/package.json\nRUN npm install\n\nCOPY . /usr/src/app\n"
  },
  {
    "path": "node-microservice-starter/users/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo_text.svg\" width=\"320\" alt=\"Nest Logo\" /></a>\n</p>\n\n[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master\n[travis-url]: https://travis-ci.org/nestjs/nest\n[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux\n[linux-url]: https://travis-ci.org/nestjs/nest\n  \n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"blank\">Node.js</a> framework for building efficient and scalable server-side applications, heavily inspired by <a href=\"https://angular.io\" target=\"blank\">Angular</a>.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\"><img src=\"https://img.shields.io/npm/dm/@nestjs/core.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://travis-ci.org/nestjs/nest\"><img src=\"https://api.travis-ci.org/nestjs/nest.svg?branch=master\" alt=\"Travis\" /></a>\n<a href=\"https://travis-ci.org/nestjs/nest\"><img src=\"https://img.shields.io/travis/nestjs/nest/master.svg?label=linux\" alt=\"Linux\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#5\" alt=\"Coverage\" /></a>\n<a href=\"https://gitter.im/nestjs/nestjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge\"><img src=\"https://badges.gitter.im/nestjs/nestjs.svg\" alt=\"Gitter\" /></a>\n<a href=\"https://opencollective.com/nest#backer\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\"><img src=\"https://img.shields.io/badge/Donate-PayPal-dc3d53.svg\"/></a>\n  <a href=\"https://twitter.com/nestframework\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\n  Nest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "node-microservice-starter/users/nest-cli.json",
    "content": "{\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "node-microservice-starter/users/package.json",
    "content": "{\n  \"name\": \"users\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^7.0.0\",\n    \"@nestjs/core\": \"^7.0.0\",\n    \"@nestjs/platform-express\": \"^7.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rimraf\": \"^3.0.2\",\n    \"rxjs\": \"^6.5.4\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^7.0.0\",\n    \"@nestjs/schematics\": \"^7.0.0\",\n    \"@nestjs/testing\": \"^7.0.0\",\n    \"@types/express\": \"^4.17.3\",\n    \"@types/jest\": \"26.0.10\",\n    \"@types/node\": \"^13.9.1\",\n    \"@types/supertest\": \"^2.0.8\",\n    \"@typescript-eslint/eslint-plugin\": \"3.9.1\",\n    \"@typescript-eslint/parser\": \"3.9.1\",\n    \"eslint\": \"7.7.0\",\n    \"eslint-config-prettier\": \"^6.10.0\",\n    \"eslint-plugin-import\": \"^2.20.1\",\n    \"jest\": \"26.4.2\",\n    \"prettier\": \"^1.19.1\",\n    \"supertest\": \"^4.0.2\",\n    \"ts-jest\": \"26.2.0\",\n    \"ts-loader\": \"^6.2.1\",\n    \"ts-node\": \"9.0.0\",\n    \"tsconfig-paths\": \"^3.9.0\",\n    \"typescript\": \"^3.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".spec.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "node-microservice-starter/users/src/app.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\ndescribe('AppController', () => {\n  let appController: AppController;\n\n  beforeEach(async () => {\n    const app: TestingModule = await Test.createTestingModule({\n      controllers: [AppController],\n      providers: [AppService],\n    }).compile();\n\n    appController = app.get<AppController>(AppController);\n  });\n\n  describe('root', () => {\n    it('should return \"Hello World!\"', () => {\n      expect(appController.getHello()).toBe('Hello World!');\n    });\n  });\n});\n"
  },
  {
    "path": "node-microservice-starter/users/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "node-microservice-starter/users/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "node-microservice-starter/users/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "node-microservice-starter/users/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "node-microservice-starter/users/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "node-microservice-starter/users/test/jest-e2e.json",
    "content": "{\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \".\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-spec.ts$\",\n  \"transform\": {\n    \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n  }\n}\n"
  },
  {
    "path": "node-microservice-starter/users/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "node-microservice-starter/users/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/.dockerignore",
    "content": "# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Dependency directories\nnode_modules/\n\n# 0x directories\n*.0x/"
  },
  {
    "path": "nodejs-cqrs-pattern/.gitignore",
    "content": "### https://github.com/github/gitignore/blob/master/Node.gitignore\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\nvendor/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless\n\n# Distribution files\ndist/\n\n# Routes (autogenerated)\nsrc/routes/\n\n# Swagger spec\napi/swagger-spec/swagger.json\n\n# 0x\n*.0x/\n\n# Event Store\neventstore/"
  },
  {
    "path": "nodejs-cqrs-pattern/Dockerfile",
    "content": "### BASE\nFROM node:dubnium-alpine AS base\nLABEL maintainer \"Qasim Soomro <qasim@soomro.com>\"\n# Set the working directory\nWORKDIR /app\n# Copy project specification and dependencies lock files\nCOPY package.json yarn.lock tsconfig.json /tmp/\n# Install yarn\nRUN apk --no-cache add yarn\n\n### DEPENDENCIES\nFROM base AS dependencies\n# Install Node.js dependencies\nRUN cd /tmp && yarn --pure-lockfile\n\n### RELEASE\nFROM base AS development\n# Copy app sources\nCOPY . .\n# Copy dependencies\nCOPY --from=dependencies /tmp/node_modules ./node_modules\n# Expose application port\nEXPOSE 7070\n"
  },
  {
    "path": "nodejs-cqrs-pattern/README.md",
    "content": "<p align=\"center\">\n  <img src=\"https://cdn-images-1.medium.com/max/1200/1*feM_-VHhK670LlEQekesKg.png\" width=\"320\" alt=\"Logo\" />\n</p>\n  \n<p align=\"center\">A Node.js CQRS/ES Swagger API Microservice Boilerplate</p>\n\n\n## Description\n\nThis is an application boilerplate that demonstrates how to use Nest.js and Event Store to create a RESTful Users API microservice.\n\nPlease note that commands have been implemented and they do write into the Event Store, however, queries for denormalized views have some boilerplate but it is up to you to implement them using your favorite database technology of choice.\n\nIn case you don't feel like downloading dependencies locally, I've added support for Docker so follow those instructions in \"Running the app\" and you'll have everything up and running in less than 2 minutes.\n\n## Dependency Table\n| Name        | Version           |\n| ------------- |:-------------: |\n| [EventStore](https://eventstore.org)      | latest |\n| [Node.js](https://nodejs.org)      | Dubnium      |\n| [TypeScript](https://www.typescriptlang.org) | 3      |\n| [Docker Compose](https://docker.com) | 3      |\n\n## Installation\n\n```bash\n$ yarn\n```\n\n## Running the app\n\n```bash\n# development\n$ yarn start\n\n# watch mode\n$ yarn start:dev\n\n# production mode\n$ yarn start:prod\n\n# analyze production mode\n$ yarn start:analyze\n\n# using with Docker\n$ ./scripts/up.sh # to start\n$ ./scripts/down.sh # to stop\n```\n\n## Relateds Links\nMedium Article (Part 1):\nhttps://medium.com/@qasimsoomro/building-microservices-using-node-js-with-ddd-cqrs-and-event-sourcing-part-1-of-2-52e0dc3d81df\n\nMedium Article (Part 2):\nhttps://medium.com/@qasimsoomro/building-microservices-using-node-js-with-ddd-cqrs-and-event-sourcing-part-2-of-2-9a5f6708e0f\n\nSwagger Explorer URL: http://localhost:7070/api\n\nEvent Store URL: http://localhost:2113\n\n## Test\n\n```bash\n# unit tests\n$ yarn test\n\n# e2e tests\n$ yarn test:e2e\n\n# test coverage\n$ yarn test:cov\n```\n\n## Release History\n* 0.1.0\n    * The first proper release\n    * CHANGE: Minimalist users app using Event Store\n* 0.0.1\n    * Work in progress"
  },
  {
    "path": "nodejs-cqrs-pattern/config.ts",
    "content": "import dotenv from 'dotenv';\nimport pkg from './package.json';\n\n// Load environment variables from .env file\ndotenv.config();\n\nconst envDevelopmentName = 'development';\nconst env = process.env.NODE_ENV || envDevelopmentName;\nconst configs = {\n  base: {\n    ENV: env,\n    DEV: env === envDevelopmentName,\n    // General\n    NAME: process.env.APP_NAME || pkg.name,\n    TITLE: process.env.APP_TITLE || 'Users',\n    DESCRIPTION: process.env.APP_DESCRIPTION || 'Users API Microservice',\n    // API\n    PREFIX: process.env.APP_PREFIX || 'v1',\n    VERSION: process.env.APP_VERSION || '1.0',\n    API_EXPLORER_PATH: process.env.APP_API_EXPLORER_PATH || '/api',\n    // Server\n    HOST: process.env.APP_HOST || '0.0.0.0',\n    PORT: process.env.APP_PORT || 7070,\n    // Event Store\n    EVENT_STORE_SETTINGS: {\n      protocol: process.env.EVENT_STORE_PROTOCOL || 'http',\n      hostname: process.env.EVENT_STORE_HOSTNAME || '0.0.0.0',\n      tcpPort: process.env.EVENT_STORE_TCP_PORT ||  1113,\n      httpPort: process.env.EVENT_STORE_HTTP_PORT ||  2113,\n      credentials: {\n        username: process.env.EVENT_STORE_CREDENTIALS_USERNAME ||  'admin',\n        password: process.env.EVENT_STORE_CREDENTIALS_PASSWORD ||  'changeit',\n      },\n      poolOptions: {\n        min: process.env.EVENT_STORE_POOLOPTIONS_MIN || 1,\n        max: process.env.EVENT_STORE_POOLOPTIONS_MAX || 10,\n      },\n    },\n  },\n  development: {},\n  production: {\n    PORT: process.env.APP_PORT || 7071,\n  },\n  test: {\n    PORT: 7072,\n  },\n};\nconst config = {...configs.base, ...configs[env]};\n\nexport {config};\n"
  },
  {
    "path": "nodejs-cqrs-pattern/docker-compose.yml",
    "content": "# Documentation\n# https://docs.docker.com/compose/compose-file\n\nversion: '3'\n\nservices:\n  eventstore:\n    image: eventstore/eventstore\n    ports:\n      - 2113:2113\n      - 1113:1113\n    environment:\n      - EVENTSTORE_RUN_PROJECTIONS=All\n      - EVENTSTORE_START_STANDARD_PROJECTIONS=true\n    networks:\n      - backend\n\n  boilerplate-nodejs-cqrs-es-swagger:\n    build:\n      context: \".\"\n    command: ${CONTAINER_COMMAND}\n    restart: always\n    deploy:\n      mode: replicated\n      replicas: ${CONTAINER_SCALE}\n    depends_on:\n      - eventstore\n    env_file:\n      - \"./.env\"\n    environment:\n      - EVENT_STORE_HOSTNAME=eventstore\n    ports:\n      - \"${CONTAINER_PORT}:7070\"\n    volumes:\n      - \"./src:/app/src\"\n    links:\n      - eventstore\n    networks:\n      - backend\n\nnetworks:\n  backend:\n    driver: bridge\n"
  },
  {
    "path": "nodejs-cqrs-pattern/docs/README.md",
    "content": "# `/docs`\n\nDesign and user documents."
  },
  {
    "path": "nodejs-cqrs-pattern/githooks/README.md",
    "content": "# `/githooks`\n\nGit hooks.\n"
  },
  {
    "path": "nodejs-cqrs-pattern/nest-cli.json",
    "content": "{\n  \"language\": \"ts\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/nodemon-debug.json",
    "content": "{\n  \"watch\": [\"src\"],\n  \"ext\": \"ts\",\n  \"ignore\": [\"src/**/*.spec.ts\"],\n  \"exec\": \"node --inspect-brk -r ts-node/register src/main.ts\"\n}"
  },
  {
    "path": "nodejs-cqrs-pattern/nodemon.json",
    "content": "{\n  \"watch\": [\"src\"],\n  \"ext\": \"ts\",\n  \"ignore\": [\"src/**/*.spec.ts\"],\n  \"exec\": \"ts-node -r tsconfig-paths/register src/main.ts\",\n  \"events\": {\n    \"restart\": \"osascript -e 'display notification \\\"boilerplate-nodejs-cqrs-es-swagger restarted\\\" with title \\\"nodemon\\\"'\"\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/package.json",
    "content": "{\n  \"name\": \"boilerplate-nodejs-cqrs-es-swagger\",\n  \"version\": \"0.0.0\",\n  \"description\": \"description\",\n  \"author\": {\n    \"name\": \"Qasim Soomro\",\n    \"email\": \"qasim@soomro.com\",\n    \"url\": \"http://www.qasimsoomro.com\"\n  },\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"build\": \"rm -rf dist && tsc\",\n    \"build:docker\": \"docker build --force-rm -t boilerplate-nodejs-cqrs-es-swagger .\",\n    \"start\": \"ts-node -r tsconfig-paths/register src/main.ts\",\n    \"start:dev\": \"nodemon\",\n    \"start:debug\": \"nodemon --config nodemon-debug.json\",\n    \"prestart:prod\": \"npm run build --scripts-prepend-node-path\",\n    \"start:prod\": \"node dist/src/main.js\",\n    \"start:prod:analyze\": \"npm run prestart:prod && 0x dist/src/main.js\",\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^5.1.0\",\n    \"@nestjs/core\": \"^5.1.0\",\n    \"@nestjs/cqrs\": \"^5.1.1\",\n    \"@nestjs/microservices\": \"^5.7.3\",\n    \"@nestjs/swagger\": \"^2.5.1\",\n    \"class-transformer\": \"^0.2.0\",\n    \"class-validator\": \"^0.9.1\",\n    \"cli-color\": \"^1.4.0\",\n    \"dotenv\": \"^6.0.0\",\n    \"fastify\": \"^1.13.0\",\n    \"fastify-cors\": \"^0.2.0\",\n    \"fastify-formbody\": \"^2.0.1\",\n    \"fastify-swagger\": \"^0.15.1\",\n    \"geteventstore-promise\": \"^3.1.1\",\n    \"logform\": \"^2.1.2\",\n    \"reflect-metadata\": \"^0.1.12\",\n    \"rxjs\": \"^6.2.2\",\n    \"rxjs-compat\": \"^6.4.0\",\n    \"strict-event-emitter-types\": \"^2.0.0\",\n    \"typescript\": \"^3.0.1\",\n    \"winston\": \"^3.2.1\",\n    \"xml2js\": \"^0.4.19\"\n  },\n  \"devDependencies\": {\n    \"0x\": \"^4.7.3\",\n    \"@nestjs/testing\": \"^5.1.0\",\n    \"@types/express\": \"^4.16.0\",\n    \"@types/jest\": \"^23.3.9\",\n    \"@types/node\": \"^10.7.1\",\n    \"@types/supertest\": \"^2.0.5\",\n    \"jest\": \"^23.5.0\",\n    \"nodemon\": \"^1.18.3\",\n    \"prettier\": \"^1.14.2\",\n    \"rimraf\": \"^2.6.2\",\n    \"supertest\": \"^3.1.0\",\n    \"ts-jest\": \"^23.1.3\",\n    \"ts-loader\": \"^4.4.2\",\n    \"ts-node\": \"^7.0.1\",\n    \"tsconfig-paths\": \"^3.5.0\",\n    \"tslint\": \"5.11.0\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".spec.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/scripts/down.sh",
    "content": "#!/bin/sh\n\nexport DIR_DATA_PATH=\"$PWD\"\n\nexport CONTAINER_COMMAND=\"yarn start:dev\"\nexport CONTAINER_SCALE=\"1\"\nexport CONTAINER_PORT=\"7070\"\n\ndocker-compose down\n"
  },
  {
    "path": "nodejs-cqrs-pattern/scripts/up.sh",
    "content": "#!/bin/sh\n\nexport DIR_DATA_PATH=\"$PWD\"\n\nexport CONTAINER_COMMAND=\"yarn start:dev\"\nexport CONTAINER_SCALE=\"1\"\nexport CONTAINER_PORT=\"7070\"\n\ndocker-compose up --build\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/app.module.ts",
    "content": "import { Module, OnModuleInit } from '@nestjs/common';\nimport { UsersModule } from './users/users.module';\nimport { EventStoreModule } from './core/event-store/event-store.module';\n\n@Module({\n  imports: [\n    EventStoreModule.forRoot(),\n    /** ------------- */\n    UsersModule,\n  ],\n})\nexport class AppModule implements OnModuleInit {\n  async onModuleInit() {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/core/event-store/event-store.class.ts",
    "content": "import { TCPClient, EventFactory} from 'geteventstore-promise';\n\n/**\n * @class EventStore\n * @description EventStore.org\n */\nexport class EventStore {\n  [x: string]: any;\n\n  /**\n   * @constructor\n   */\n  constructor() {\n    this.type = 'event-store';\n    this.eventFactory = new EventFactory();\n  }\n\n  connect(config) {\n    this.client = new TCPClient(config);\n    return this;\n  }\n\n  getClient() {\n    return this.client;\n  }\n\n  newEvent(name, payload) {\n    return this.eventFactory.newEvent(name, payload);\n  }\n\n  close() {\n    this.client.close();\n    return this;\n  }\n}"
  },
  {
    "path": "nodejs-cqrs-pattern/src/core/event-store/event-store.interface.ts",
    "content": "export interface EventStoreMessage {\n  streamId: string;\n  eventId: string;\n  eventNumber: number;\n  eventType: string;\n  created: Date;\n  metadata: object;\n  isJson: boolean;\n  data: object;\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/core/event-store/event-store.module.ts",
    "content": "import { Global, Module, DynamicModule } from '@nestjs/common';\nimport { EventStore } from './event-store';\nimport { eventStoreProviders } from './event-store.provider';\n\n@Global()\n@Module({\n  providers: [\n    ...eventStoreProviders,\n    {\n      provide: 'EVENT_STORE_CONFIG',\n      useValue: 'EVENT_STORE_CONFIG_USE_ENV',\n    },\n  ],\n  exports: [\n    ...eventStoreProviders,\n    {\n      provide: 'EVENT_STORE_CONFIG',\n      useValue: 'EVENT_STORE_CONFIG_USE_ENV',\n    },\n  ],\n})\nexport class EventStoreModule {\n  static forRoot(): DynamicModule {\n    return {\n      module: EventStoreModule,\n    };\n  }\n\n  static forFeature(): DynamicModule {\n    return {\n      module: EventStoreModule,\n      providers: [\n        EventStore,\n      ],\n      exports: [\n        EventStore,\n      ],\n    };\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/core/event-store/event-store.provider.ts",
    "content": "import {config} from '../../../config';\nimport {EventStore} from './event-store.class';\n\nexport const eventStoreProviders = [\n  {\n    provide: 'EVENT_STORE_PROVIDER',\n    useFactory: (\n        eventStoreConfig?: any,\n    ): any => {\n        if (eventStoreConfig === 'EVENT_STORE_CONFIG_USE_ENV') {\n          return new EventStore();\n        }\n    },\n    inject: ['EVENT_STORE_CONFIG'],\n  },\n];\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/core/event-store/event-store.ts",
    "content": "import { Injectable, Inject, OnModuleDestroy, OnModuleInit } from '@nestjs/common';\nimport { IEventPublisher } from '@nestjs/cqrs/dist/interfaces/events/event-publisher.interface';\nimport { IMessageSource } from '@nestjs/cqrs/dist/interfaces/events/message-source.interface';\nimport { IEvent } from '@nestjs/cqrs/dist/interfaces/events/event.interface';\nimport { Subject, fromEvent } from 'rxjs';\nimport * as xml2js from 'xml2js';\nimport * as http from 'http';\nimport { config } from '../../../config';\n\nconst eventStoreHostUrl = config.EVENT_STORE_SETTINGS.protocol +\n  `://${config.EVENT_STORE_SETTINGS.hostname}:${config.EVENT_STORE_SETTINGS.httpPort}/streams/`;\n\n/**\n * @class EventStore\n * @description The EventStore.org bridge. By design, the domain category\n * (i.e. user) events are being subscribed to. Upon events being received,\n * internal event handlers are responsible for the handling of events.\n */\n@Injectable()\nexport class EventStore implements IEventPublisher, IMessageSource {\n  private eventStore: any;\n  private eventHandlers: object;\n  private category: string;\n\n  constructor(@Inject('EVENT_STORE_PROVIDER') eventStore: any) {\n    this.category = 'users';\n    this.eventStore = eventStore;\n    this.eventStore.connect({\n      hostname: config.EVENT_STORE_SETTINGS.hostname,\n      port: config.EVENT_STORE_SETTINGS.tcpPort,\n      credentials: config.EVENT_STORE_SETTINGS.credentials,\n      poolOptions: config.EVENT_STORE_SETTINGS.poolOptions,\n    });\n  }\n\n  async publish<T extends IEvent>(event: T) {\n    const message = JSON.parse(JSON.stringify(event));\n    const userId = message.userId || message.userDto.userId;\n    const streamName = `${this.category}-${userId}`;\n    const type = event.constructor.name;\n    try {\n      await this.eventStore.client.writeEvent(streamName, type, event);\n    } catch (err) {\n      console.trace(err);\n    }\n  }\n\n  /**\n   * @description Event Store bridge subscribes to domain category stream\n   * @param subject\n   */\n  async bridgeEventsTo<T extends IEvent>(subject: Subject<T>) {\n    const streamName = `$ce-${this.category}`;\n\n    const onEvent = async (event) => {\n      const eventUrl = eventStoreHostUrl +\n        `${event.metadata.$o}/${event.data.split('@')[0]}`;\n      http.get(eventUrl, (res) => {\n        res.setEncoding('utf8');\n        let rawData = '';\n        res.on('data', (chunk) => { rawData += chunk; });\n        res.on('end', () => {\n          xml2js.parseString(rawData, (err, result) => {\n            if (err) {\n              console.trace(err);\n              return;\n            }\n            const content = result['atom:entry']['atom:content'][0];\n            const eventType = content.eventType[0];\n            const data = content.data[0];\n            event = this.eventHandlers[eventType](...Object.values(data));\n            subject.next(event);\n          });\n        });\n      });\n    };\n\n    const onDropped = (subscription, reason, error) => {\n      console.trace(subscription, reason, error);\n    };\n\n    try {\n      await this.eventStore.client.subscribeToStream(streamName, onEvent, onDropped, false);\n    } catch (err) {\n      console.trace(err);\n    }\n  }\n\n  setEventHandlers(eventHandlers) {\n    this.eventHandlers = eventHandlers;\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/main.ts",
    "content": "import { NestFactory, FastifyAdapter } from '@nestjs/core';\nimport { ValidationPipe, Logger } from '@nestjs/common';\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';\nimport fastifyCors from 'fastify-cors';\nimport { AppModule } from './app.module';\nimport { config } from '../config';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule, new FastifyAdapter({\n    trustProxy: true,\n  }));\n  const documentOptions = new DocumentBuilder()\n    .setTitle(config.TITLE)\n    .setDescription(config.DESCRIPTION)\n    .setVersion(config.VERSION)\n    .setBasePath(`/${config.PREFIX}`)\n    .build();\n  const document = SwaggerModule.createDocument(app, documentOptions);\n  const validationOptions = {\n    skipMissingProperties: true,\n    validationError: { target: false },\n  };\n  /*--------------------------------------------*/\n  app.useGlobalPipes(new ValidationPipe(validationOptions));\n  app.setGlobalPrefix(config.PREFIX);\n  app.register(fastifyCors, {\n    origin: true,\n  });\n  SwaggerModule.setup(config.API_EXPLORER_PATH, app, document);\n  await app.listen(config.PORT, config.HOST);\n  Logger.log(`Server listening on port ${config.PORT}`, 'Bootstrap');\n}\n\nbootstrap();\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/handlers/create-user.handler.ts",
    "content": "import { EventPublisher, ICommandHandler, CommandHandler } from '@nestjs/cqrs';\nimport { CreateUserCommand } from '../impl/create-user.command';\nimport { UserRepository } from '../../repository/user.repository';\nimport { Logger } from '@nestjs/common';\n\n@CommandHandler(CreateUserCommand)\nexport class CreateUserHandler\n  implements ICommandHandler<CreateUserCommand> {\n  constructor(\n    private readonly repository: UserRepository,\n    private readonly publisher: EventPublisher,\n  ) {}\n\n  async execute(command: CreateUserCommand, resolve: (value?) => void) {\n    Logger.log('Async CreateUserHandler...', 'CreateUserCommand');\n\n    const {userDto} = command;\n    const user = this.publisher.mergeObjectContext(\n      await this.repository.createUser(userDto),\n    );\n    user.commit();\n    resolve();\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/handlers/delete-user.handler.ts",
    "content": "import { EventPublisher, ICommandHandler, CommandHandler } from '@nestjs/cqrs';\nimport { DeleteUserCommand } from '../impl/delete-user.command';\nimport { UserRepository } from '../../repository/user.repository';\nimport { Logger } from '@nestjs/common';\n\n@CommandHandler(DeleteUserCommand)\nexport class DeleteUserHandler\n  implements ICommandHandler<DeleteUserCommand> {\n  constructor(\n    private readonly repository: UserRepository,\n    private readonly publisher: EventPublisher,\n  ) {}\n\n  async execute(command: DeleteUserCommand, resolve: (value?) => void) {\n    Logger.log('Async DeleteUserHandler...', 'DeleteUserCommand');\n    const {userDto} = command;\n    const user = this.publisher.mergeObjectContext(\n      await this.repository.deleteUser(userDto),\n    );\n    user.commit();\n    resolve();\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/handlers/index.ts",
    "content": "import { CreateUserHandler } from './create-user.handler';\nimport { DeleteUserHandler } from './delete-user.handler';\nimport { UpdateUserHandler } from './update-user.handler';\nimport { WelcomeUserHandler } from './welcome-user.handler';\n\nexport const CommandHandlers = [\n  CreateUserHandler,\n  DeleteUserHandler,\n  UpdateUserHandler,\n  WelcomeUserHandler,\n];\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/handlers/update-user.handler.ts",
    "content": "import { EventPublisher, ICommandHandler, CommandHandler } from '@nestjs/cqrs';\nimport { UpdateUserCommand } from '../impl/update-user.command';\nimport { UserRepository } from '../../repository/user.repository';\nimport { Logger } from '@nestjs/common';\n\n@CommandHandler(UpdateUserCommand)\nexport class UpdateUserHandler\n  implements ICommandHandler<UpdateUserCommand> {\n  constructor(\n    private readonly repository: UserRepository,\n    private readonly publisher: EventPublisher,\n  ) {}\n\n  async execute(command: UpdateUserCommand, resolve: (value?) => void) {\n    Logger.log('Async UpdateUserHandler...', 'UpdateUserCommand');\n\n    const {userDto} = command;\n    const user = this.publisher.mergeObjectContext(\n      await this.repository.updateUser(userDto),\n    );\n    user.commit();\n    resolve();\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/handlers/welcome-user.handler.ts",
    "content": "import { EventPublisher, ICommandHandler, CommandHandler } from '@nestjs/cqrs';\nimport { WelcomeUserCommand } from '../impl/welcome-user.command';\nimport { UserRepository } from '../../repository/user.repository';\nimport { Logger } from '@nestjs/common';\n\n@CommandHandler(WelcomeUserCommand)\nexport class WelcomeUserHandler\n  implements ICommandHandler<WelcomeUserCommand> {\n  constructor(\n    private readonly repository: UserRepository,\n    private readonly publisher: EventPublisher,\n  ) {}\n\n  async execute(command: WelcomeUserCommand, resolve: (value?) => void) {\n    Logger.log('Async WelcomeUserHandler...', 'WelcomeUserCommand');\n    const {userId} = command;\n    const user = this.publisher.mergeObjectContext(\n      await this.repository.welcomeUser({userId}),\n    );\n    user.commit();\n    resolve();\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/impl/create-user.command.ts",
    "content": "import { ICommand } from '@nestjs/cqrs';\nimport { UserDto } from '../../dtos/users.dto';\n\nexport class CreateUserCommand implements ICommand {\n  constructor(\n    public readonly userDto: UserDto,\n  ) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/impl/delete-user.command.ts",
    "content": "import { ICommand } from '@nestjs/cqrs';\nimport { UserIdRequestParamsDto } from '../../dtos/users.dto';\n\nexport class DeleteUserCommand implements ICommand {\n  constructor(\n    public readonly userDto: UserIdRequestParamsDto,\n  ) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/impl/update-user.command.ts",
    "content": "import { ICommand } from '@nestjs/cqrs';\nimport { UserDto } from '../../dtos/users.dto';\n\nexport class UpdateUserCommand implements ICommand {\n  constructor(\n    public readonly userDto: UserDto,\n  ) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/commands/impl/welcome-user.command.ts",
    "content": "import { ICommand } from '@nestjs/cqrs';\n\nexport class WelcomeUserCommand implements ICommand {\n  constructor(\n    public readonly userId: string,\n  ) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/controllers/users.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersController } from './users.controller';\nimport { UsersService } from '../services/users.service';\n\ndescribe('Users Controller', () => {\n  let module: TestingModule;\n  beforeAll(async () => {\n    module = await Test.createTestingModule({\n      controllers: [UsersController],\n      providers: [UsersService],\n    }).compile();\n  });\n  it('should be defined', () => {\n    const controller: UsersController = module.get<UsersController>(UsersController);\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/controllers/users.controller.ts",
    "content": "import { Controller, Get, Post, Param, Body, Delete, Put } from '@nestjs/common';\nimport { ApiUseTags, ApiResponse, ApiOperation } from '@nestjs/swagger';\nimport { UserIdRequestParamsDto } from '../dtos/users.dto';\nimport { UserDto } from '../dtos/users.dto';\nimport { UsersService } from '../services/users.service';\n\n@Controller('users')\n@ApiUseTags('Users')\nexport class UsersController {\n  constructor(private readonly usersService: UsersService) { }\n\n  /* Create User */\n  /*--------------------------------------------*/\n  @ApiOperation({ title: 'Create User' })\n  @ApiResponse({ status: 200, description: 'Create User.' })\n  @Post()\n  async createUser(@Body() userDto: UserDto): Promise<UserDto> {\n    const userId = Math.floor(Math.random() * (999 - 100 + 1) + 100);\n    return this.usersService.createUser({...{userId}, ...userDto});\n  }\n\n  /* Update User */\n  /*--------------------------------------------*/\n  @ApiOperation({ title: 'Update User' })\n  @ApiResponse({ status: 200, description: 'Update User.' })\n  @Put(':userId')\n  async updateUser(@Param() userId: UserIdRequestParamsDto, @Body() userDto: UserDto) {\n    return this.usersService.updateUser({...userId, ...userDto});\n  }\n\n  /* Delete User */\n  /*--------------------------------------------*/\n  @ApiOperation({ title: 'Delete User' })\n  @ApiResponse({ status: 200, description: 'Delete User.' })\n  @Delete(':userId')\n  async deleteUser(@Param() userId: UserIdRequestParamsDto) {\n    return this.usersService.deleteUser(userId);\n  }\n\n  /* TODO: List Users */\n  /*--------------------------------------------*/\n  @ApiOperation({ title: 'List Users' })\n  @ApiResponse({ status: 200, description: 'List Users.' })\n  @Get()\n  async findUsers(@Param() param) {\n    return this.usersService.findUsers();\n  }\n\n  /* TODO: Find User */\n  /*--------------------------------------------*/\n  @ApiOperation({ title: 'Get User' })\n  @ApiResponse({ status: 200, description: 'Get User.' })\n  @Get(':userId')\n  async findOneUser(@Param() userId: UserIdRequestParamsDto) {\n    return this.usersService.findUsers();\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/dtos/users.dto.ts",
    "content": "import { IsString } from 'class-validator';\n\nexport class UserIdRequestParamsDto {\n  @IsString()\n  readonly userId!: string;\n}\n\nexport class UserDto {\n  @IsString()\n  readonly userId!: string;\n  @IsString()\n  readonly firstName!: string;\n  @IsString()\n  readonly lastName!: string;\n}"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/handlers/index.ts",
    "content": "import { UserCreatedHandler} from './user-created.handler';\nimport { UserUpdatedHandler} from './user-updated.handler';\nimport { UserDeletedHandler} from './user-deleted.handler';\nimport { UserWelcomedHandler} from './user-welcomed.handler';\n\nexport const EventHandlers = [\n  UserCreatedHandler,\n  UserUpdatedHandler,\n  UserDeletedHandler,\n  UserWelcomedHandler,\n];\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/handlers/user-created.handler.ts",
    "content": "\nimport { IEventHandler, EventsHandler } from '@nestjs/cqrs';\nimport { UserCreatedEvent } from '../impl/user-created.event';\nimport { Logger } from '@nestjs/common';\n\n@EventsHandler(UserCreatedEvent)\nexport class UserCreatedHandler\n  implements IEventHandler<UserCreatedEvent> {\n  handle(event: UserCreatedEvent) {\n    Logger.log(event, 'UserCreatedEvent'); // write here\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/handlers/user-deleted.handler.ts",
    "content": "import { IEventHandler, EventsHandler } from '@nestjs/cqrs';\nimport { UserDeletedEvent } from '../impl/user-deleted.event';\nimport { Logger } from '@nestjs/common';\n\n@EventsHandler(UserDeletedEvent)\nexport class UserDeletedHandler\n  implements IEventHandler<UserDeletedEvent> {\n  handle(event: UserDeletedEvent) {\n    Logger.log(event, 'UserDeletedEvent'); // write here\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/handlers/user-updated.handler.ts",
    "content": "import { IEventHandler, EventsHandler } from '@nestjs/cqrs';\nimport { UserUpdatedEvent } from '../impl/user-updated.event';\nimport { Logger } from '@nestjs/common';\n\n@EventsHandler(UserUpdatedEvent)\nexport class UserUpdatedHandler\n  implements IEventHandler<UserUpdatedEvent> {\n  handle(event: UserUpdatedEvent) {\n    Logger.log(event, 'UserUpdatedEvent'); // write here\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/handlers/user-welcomed.handler.ts",
    "content": "import { IEventHandler, EventsHandler } from '@nestjs/cqrs';\nimport { UserWelcomedEvent } from '../impl/user-welcomed.event';\nimport { Logger } from '@nestjs/common';\n\n@EventsHandler(UserWelcomedEvent)\nexport class UserWelcomedHandler\n  implements IEventHandler<UserWelcomedEvent> {\n  handle(event: UserWelcomedEvent) {\n    Logger.log(event, 'UserWelcomedEvent'); // write here\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/impl/user-created.event.ts",
    "content": "import { IEvent } from '@nestjs/cqrs';\nimport { UserDto } from '../../dtos/users.dto';\n\nexport class UserCreatedEvent implements IEvent {\n  constructor(\n    public readonly userDto: UserDto) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/impl/user-deleted.event.ts",
    "content": "import { IEvent } from '@nestjs/cqrs';\n\nexport class UserDeletedEvent implements IEvent {\n  constructor(\n    public readonly userId: string) {}\n}"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/impl/user-updated.event.ts",
    "content": "import { IEvent } from '@nestjs/cqrs';\nimport { UserDto } from '../../dtos/users.dto';\n\nexport class UserUpdatedEvent implements IEvent {\n  constructor(\n    public readonly userDto: UserDto) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/events/impl/user-welcomed.event.ts",
    "content": "import { IEvent } from '@nestjs/cqrs';\n\nexport class UserWelcomedEvent implements IEvent {\n  constructor(\n    public readonly userId: string) {}\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/models/user.model.ts",
    "content": "import { AggregateRoot } from '@nestjs/cqrs';\nimport { UserCreatedEvent } from '../events/impl/user-created.event';\nimport { UserUpdatedEvent } from '../events/impl/user-updated.event';\nimport { UserDeletedEvent } from '../events/impl/user-deleted.event';\nimport { UserWelcomedEvent } from '../events/impl/user-welcomed.event';\nimport { UserDto } from '../dtos/users.dto';\n\nexport class User extends AggregateRoot {\n  [x: string]: any;\n\n  constructor(private readonly id: string | undefined) {\n    super();\n  }\n\n  setData(data) {\n    this.data = data;\n  }\n\n  createUser() {\n    this.apply(new UserCreatedEvent(this.data));\n  }\n\n  updateUser() {\n    this.apply(new UserUpdatedEvent(this.data));\n  }\n\n  welcomeUser() {\n    this.apply(new UserWelcomedEvent(this.id));\n  }\n\n  deleteUser() {\n    this.apply(new UserDeletedEvent(this.id));\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/repository/user.repository.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { User } from '../models/user.model';\n\n@Injectable()\nexport class UserRepository {\n  async createUser(userDto) {\n    const user = new User(undefined);\n    user.setData(userDto);\n    user.createUser();\n    return user;\n  }\n\n  async updateUser(userDto) {\n    const user = new User(userDto.userId);\n    user.setData(userDto);\n    user.updateUser();\n    return user;\n  }\n\n  async deleteUser(userDto) {\n    const user = new User(userDto.userId);\n    user.deleteUser();\n    return user;\n  }\n\n  async welcomeUser(userDto) {\n    const user = new User(userDto.userId);\n    user.welcomeUser();\n    return user;\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/sagas/users.sagas.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Observable } from 'rxjs';\nimport { ICommand, EventObservable } from '@nestjs/cqrs';\nimport { UserCreatedEvent } from '../events/impl/user-created.event';\nimport { WelcomeUserCommand } from '../commands/impl/welcome-user.command';\nimport { delay, map } from 'rxjs/operators';\n\n@Injectable()\nexport class UsersSagas {\n  userCreated = (events$: EventObservable<any>): Observable<ICommand> => {\n    return events$\n      .ofType(UserCreatedEvent)\n      .pipe(\n        delay(1000),\n        map(event => {\n          Logger.log('Inside [UsersSagas] Saga', 'UsersSagas');\n          const userId = event.userDto[0].userId[0];\n          return new WelcomeUserCommand(userId);\n        }),\n      );\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/services/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CommandBus } from '@nestjs/cqrs';\nimport { UserIdRequestParamsDto } from '../dtos/users.dto';\nimport { UserDto } from '../dtos/users.dto';\nimport { CreateUserCommand } from '../commands/impl/create-user.command';\nimport { UpdateUserCommand } from '../commands/impl/update-user.command';\nimport { DeleteUserCommand } from '../commands/impl/delete-user.command';\n\n@Injectable()\nexport class UsersService {\n  constructor(private readonly commandBus: CommandBus) {}\n\n  async createUser(user: UserDto) {\n    return await this.commandBus.execute(\n      new CreateUserCommand(user),\n    );\n  }\n\n  async updateUser(user: UserDto) {\n    return await this.commandBus.execute(\n      new UpdateUserCommand(user),\n    );\n  }\n\n  async deleteUser(user: UserIdRequestParamsDto) {\n    return await this.commandBus.execute(\n      new DeleteUserCommand(user),\n    );\n  }\n\n  async findUsers() {\n    // TODO\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/src/users/users.module.ts",
    "content": "import { CommandBus, EventBus, CQRSModule } from '@nestjs/cqrs';\nimport { OnModuleInit, Module } from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { CommandHandlers } from './commands/handlers';\nimport { EventHandlers } from './events/handlers';\nimport { UsersSagas } from './sagas/users.sagas';\nimport { UsersController } from './controllers/users.controller';\nimport { UsersService } from './services/users.service';\nimport { UserRepository } from './repository/user.repository';\nimport { EventStoreModule } from '../core/event-store/event-store.module';\nimport { EventStore } from '../core/event-store/event-store';\nimport { UserCreatedEvent } from './events/impl/user-created.event';\nimport { UserDeletedEvent } from './events/impl/user-deleted.event';\nimport { UserUpdatedEvent } from './events/impl/user-updated.event';\nimport { UserWelcomedEvent } from './events/impl/user-welcomed.event';\n\n@Module({\n  imports: [\n    CQRSModule,\n    EventStoreModule.forFeature(),\n  ],\n  controllers: [UsersController],\n  providers: [\n    UsersService,\n    UsersSagas,\n    ...CommandHandlers,\n    ...EventHandlers,\n    UserRepository,\n  ],\n})\nexport class UsersModule implements OnModuleInit {\n  constructor(\n    private readonly moduleRef: ModuleRef,\n    private readonly command$: CommandBus,\n    private readonly event$: EventBus,\n    private readonly usersSagas: UsersSagas,\n    private readonly eventStore: EventStore,\n  ) {}\n\n  onModuleInit() {\n    this.command$.setModuleRef(this.moduleRef);\n    this.event$.setModuleRef(this.moduleRef);\n    /** ------------ */\n    this.eventStore.setEventHandlers(this.eventHandlers);\n    this.eventStore.bridgeEventsTo((this.event$ as any).subject$);\n    this.event$.publisher = this.eventStore;\n    /** ------------ */\n    this.event$.register(EventHandlers);\n    this.command$.register(CommandHandlers);\n    this.event$.combineSagas([this.usersSagas.userCreated]);\n  }\n\n  eventHandlers = {\n    UserCreatedEvent: (data) => new UserCreatedEvent(data),\n    UserDeletedEvent: (data) => new UserDeletedEvent(data),\n    UserUpdatedEvent: (data) => new UserUpdatedEvent(data),\n    UserWelcomedEvent: (data) => new UserWelcomedEvent(data),\n  };\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/test/app.e2e-spec.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { Test } from '@nestjs/testing';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeAll(async () => {\n    const moduleFixture = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  // it('/ (GET)', () => {\n  //   return request(app.getHttpServer())\n  //     .get('/')\n  //     .expect(200)\n  //     .expect('Hello World!');\n  // });\n});\n"
  },
  {
    "path": "nodejs-cqrs-pattern/test/jest-e2e.json",
    "content": "{\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \".\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-spec.ts$\",\n  \"transform\": {\n    \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n  }\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"noImplicitAny\": false,\n    \"removeComments\": true,\n    \"noLib\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"target\": \"es6\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./src\",\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true\n  },\n  \"include\": [\n    \"src/**/*\",\n    \"pipes/*\",\n    \"middlewares/*\",\n  ],\n  \"exclude\": [\n    \"node_modules\",\n    \"**/*.spec.ts\"\n  ]\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\"**/*.spec.ts\", \"**/*.d.ts\"]\n}\n"
  },
  {
    "path": "nodejs-cqrs-pattern/tslint.json",
    "content": "{\n    \"defaultSeverity\": \"error\",\n    \"extends\": [\n        \"tslint:recommended\"\n    ],\n    \"jsRules\": {\n        \"no-unused-expression\": true\n    },\n    \"rules\": {\n        \"eofline\": false,\n        \"quotemark\": [\n            true,\n            \"single\"\n        ],\n        \"indent\": false,\n        \"member-access\": [\n            false\n        ],\n        \"ordered-imports\": [\n            false\n        ],\n        \"max-line-length\": [\n            true,\n            150\n        ],\n        \"member-ordering\": [\n            false\n        ],\n        \"curly\": false,\n        \"interface-name\": [\n            false\n        ],\n        \"array-type\": [\n            false\n        ],\n        \"no-empty-interface\": false,\n        \"no-empty\": false,\n        \"arrow-parens\": false,\n        \"object-literal-sort-keys\": false,\n        \"no-unused-expression\": false,\n        \"max-classes-per-file\": [\n            false\n        ],\n        \"variable-name\": [\n            false\n        ],\n        \"one-line\": [\n            false\n        ],\n        \"one-variable-per-declaration\": [\n            false\n        ]\n    },\n    \"rulesDirectory\": []\n}\n"
  },
  {
    "path": "nodejs-express-typescript/.editorconfig",
    "content": "################################################\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": "nodejs-express-typescript/.eslintignore",
    "content": "build/*\n\n"
  },
  {
    "path": "nodejs-express-typescript/.eslintrc.js",
    "content": "module.exports =  {\n  parser:  '@typescript-eslint/parser',  // Specifies the ESLint parser\n  extends:  [\n    'plugin:@typescript-eslint/recommended',  // Uses the recommended rules from the @typescript-eslint/eslint-plugin\n    'prettier/@typescript-eslint',  // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier\n    'plugin:prettier/recommended',  // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.\n  ],\n  parserOptions:  {\n    ecmaVersion:  2018,  // Allows for the parsing of modern ECMAScript features\n    sourceType:  'module',  // Allows for the use of imports\n  },\n  rules:  {\n    '@typescript-eslint/explicit-member-accessibility': 0,\n    '@typescript-eslint/explicit-function-return-type': 0,\n    '@typescript-eslint/no-parameter-properties': 0,\n    '@typescript-eslint/interface-name-prefix': 0\n  },\n};\n"
  },
  {
    "path": "nodejs-express-typescript/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n# dependencies\n/node_modules\n\n# misc\n.DS_Store\n.env*\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.env\nbuild"
  },
  {
    "path": "nodejs-express-typescript/.prettierrc.json",
    "content": "{\n  \"semi\": true,\n  \"trailingComma\": \"all\",\n  \"singleQuote\": true,\n  \"printWidth\": 120,\n  \"tabWidth\": 2,\n  \"arrowParens\": \"avoid\"\n}\n"
  },
  {
    "path": "nodejs-express-typescript/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Santiago Quinteros\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "nodejs-express-typescript/Procfile",
    "content": "web: node build/app.js"
  },
  {
    "path": "nodejs-express-typescript/README.md",
    "content": "# Node.js architecture 🛡️\n\n## Development\n\nWe use `node` version `10.15.0`\n\n```\nnvm install v14.0.0\n```\n\n```\nnvm use 14.0.0\n```\n\nThe first time, you will need to run\n\n```\nnpm install\n```\n\nThen just start the server with \n\n```\nnpm run start\n```\nIt uses nodemon for livereloading :peace-fingers:\n\n# API Validation\n \n By using celebrate the req.body schema becomes clary defined at route level, so even frontend devs can read what an API endpoint expects without need to writting a documentation that can get outdated quickly.\n\n ```js\n route.post('/signup', \n  celebrate({\n    body: Joi.object({\n      name: Joi.string().required(),\n      email: Joi.string().required(),\n      password: Joi.string().required(),\n    }),\n  }),\n  controller.signup)\n ```\n\n **Example error**\n\n ```json\n {\n  \"errors\": {\n    \"message\": \"child \\\"email\\\" fails because [\\\"email\\\" is required]\"\n  }\n } \n ```\n# Roadmap\n- [x] API Validation layer (Celebrate+Joi)\n- [ ] Unit tests examples\n- [x] The logging _'layer'_ \n- [ ] Add agenda dashboard\n- [x] Continuous integration with CircleCI 😍\n- [ ] Deploys script and docs for AWS Elastic Beanstalk and Heroku\n- [ ] Integration test with newman 😉\n- [ ] Instructions on typescript debugging with VSCode"
  },
  {
    "path": "nodejs-express-typescript/jest.config.js",
    "content": "// For a detailed explanation regarding each configuration property, visit:\n// https://jestjs.io/docs/en/configuration.html\n\nmodule.exports = {\n  // All imported modules in your tests should be mocked automatically\n  // automock: false,\n\n  // Stop running tests after the first failure\n  // bail: false,\n\n  // Respect \"browser\" field in package.json when resolving modules\n  // browser: false,\n\n  // The directory where Jest should store its cached dependency information\n  // cacheDirectory: \"/var/folders/bw/vvybgj3d3kgb98nzjxfmpv5c0000gn/T/jest_dx\",\n\n  // Automatically clear mock calls and instances between every test\n  // clearMocks: false,\n\n  // Indicates whether the coverage information should be collected while executing the test\n  // collectCoverage: false,\n\n  // An array of glob patterns indicating a set of files for which coverage information should be collected\n  // collectCoverageFrom: null,\n\n  // The directory where Jest should output its coverage files\n  // coverageDirectory: null,\n\n  // An array of regexp pattern strings used to skip coverage collection\n  // coveragePathIgnorePatterns: [\n  //   \"/node_modules/\"\n  // ],\n\n  // A list of reporter names that Jest uses when writing coverage reports\n  // coverageReporters: [\n  //   \"json\",\n  //   \"text\",\n  //   \"lcov\",\n  //   \"clover\"\n  // ],\n\n  // An object that configures minimum threshold enforcement for coverage results\n  // coverageThreshold: null,\n\n  // Make calling deprecated APIs throw helpful error messages\n  // errorOnDeprecated: false,\n\n  // Force coverage collection from ignored files usin a array of glob patterns\n  // forceCoverageMatch: [],\n\n  // A path to a module which exports an async function that is triggered once before all test suites\n  // globalSetup: null,\n\n  // A path to a module which exports an async function that is triggered once after all test suites\n  // globalTeardown: null,\n\n  // A set of global variables that need to be available in all test environments\n  // globals: {},\n\n  // An array of directory names to be searched recursively up from the requiring module's location\n  // moduleDirectories: [\n  //   \"node_modules\"\n  // ],\n\n  // An array of file extensions your modules use\n  moduleFileExtensions: [\n    'js',\n    'ts',\n    'json'\n  ],\n\n  // A map from regular expressions to module names that allow to stub out resources with a single module\n  // moduleNameMapper: {},\n\n  // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader\n  // modulePathIgnorePatterns: [],\n\n  // Activates notifications for test results\n  // notify: false,\n\n  // An enum that specifies notification mode. Requires { notify: true }\n  // notifyMode: \"always\",\n\n  // A preset that is used as a base for Jest's configuration\n  preset: 'ts-jest',\n\n  // Run tests from one or more projects\n  // projects: null,\n\n  // Use this configuration option to add custom reporters to Jest\n  // reporters: undefined,\n\n  // Automatically reset mock state between every test\n  // resetMocks: false,\n\n  // Reset the module registry before running each individual test\n  // resetModules: false,\n\n  // A path to a custom resolver\n  // resolver: null,\n\n  // Automatically restore mock state between every test\n  // restoreMocks: false,\n\n  // The root directory that Jest should scan for tests and modules within\n  // rootDir: null,\n\n  // A list of paths to directories that Jest should use to search for files in\n  // roots: [\n  //   \"<rootDir>\"\n  // ],\n\n  // Allows you to use a custom runner instead of Jest's default test runner\n  // runner: \"jest-runner\",\n\n  // The paths to modules that run some code to configure or set up the testing environment before each test\n  // setupFiles: [],\n\n  // The path to a module that runs some code to configure or set up the testing framework before each test\n  // setupTestFrameworkScriptFile: './tests/setup.js',\n\n  // A list of paths to snapshot serializer modules Jest should use for snapshot testing\n  // snapshotSerializers: [],\n\n  // The test environment that will be used for testing\n  testEnvironment: 'node',\n\n  // Options that will be passed to the testEnvironment\n  // testEnvironmentOptions: {},\n\n  // Adds a location field to test results\n  // testLocationInResults: false,\n\n  // The glob patterns Jest uses to detect test files\n  testMatch: [\n    // '**/?(*.)+(spec|test).js?(x)',\n    '**/?(*.)+(spec|test).ts?(x)',\n  ],\n\n  // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped\n  // testPathIgnorePatterns: [\n  //   \"/node_modules/\"\n  // ],\n\n  // The regexp pattern Jest uses to detect test files\n  // testRegex: \"\",\n\n  // This option allows the use of a custom results processor\n  // testResultsProcessor: null,\n\n  // This option allows use of a custom test runner\n  // testRunner: \"jasmine2\",\n\n  // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href\n  // testURL: \"http://localhost\",\n\n  // Setting this value to \"fake\" allows the use of fake timers for functions such as \"setTimeout\"\n  // timers: \"real\",\n\n  // A map from regular expressions to paths to transformers\n  transform: {\n    '^.+\\\\.ts?$': 'ts-jest',\n  },\n\n  // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation\n  // transformIgnorePatterns: [\n  //   \"/node_modules/\"\n  // ],\n\n  // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them\n  // unmockedModulePathPatterns: undefined,\n\n  // Indicates whether each individual test should be reported during the run\n  // verbose: null,\n\n  // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode\n  // watchPathIgnorePatterns: [],\n\n  // Whether to use watchman for file crawling\n  // watchman: true,\n};\n"
  },
  {
    "path": "nodejs-express-typescript/nodemon.json",
    "content": "{\n  \"watch\": [\n    \"src\",\n    \".env\"\n  ],\n  \"ext\": \"js,ts,json\",\n  \"ignore\": [\n    \"src/**/*.spec.ts\"\n  ],\n  \"exec\": \"ts-node  --transpile-only ./src/app.ts\"\n}"
  },
  {
    "path": "nodejs-express-typescript/package.json",
    "content": "{\n  \"name\": \"bulletproof-nodejs\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Bulletproof node.js\",\n  \"main\": \"src/app.ts\",\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"heroku-postbuild\": \"npm run build\",\n    \"start\": \"nodemon\",\n    \"inspect\": \"nodemon --inspect src/app.ts\",\n    \"test\": \"jest\",\n    \"lint\": \"npm run lint:js \",\n    \"lint:eslint\": \"eslint --ignore-path .gitignore --ext .ts\",\n    \"lint:js\": \"npm run lint:eslint src/\",\n    \"lint:fix\": \"npm run lint:js -- --fix\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/santiq/bulletproof-nodejs.git\"\n  },\n  \"keywords\": [\n    \"boilerplay\",\n    \"cron\",\n    \"jobs\",\n    \"js\",\n    \"javascript\",\n    \"typescript\",\n    \"node\",\n    \"express\"\n  ],\n  \"author\": \"Santiago Quinteros\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"argon2\": \"^0.21.0\",\n    \"body-parser\": \"^1.18.2\",\n    \"celebrate\": \"^9.1.0\",\n    \"cors\": \"^2.8.4\",\n    \"dotenv\": \"^8.2.0\",\n    \"errorhandler\": \"^1.5.0\",\n    \"express\": \"^4.16.2\",\n    \"express-jwt\": \"^6.0.0\",\n    \"jsonwebtoken\": \"^8.2.0\",\n    \"mongoose\": \"^5.7.5\",\n    \"morgan\": \"^1.9.1\",\n    \"reflect-metadata\": \"^0.1.12\",\n    \"typedi\": \"^0.8.0\",\n    \"winston\": \"^3.2.1\"\n  },\n  \"devDependencies\": {\n    \"@types/agenda\": \"^2.0.4\",\n    \"@types/express\": \"^4.16.0\",\n    \"@types/jest\": \"^23.3.8\",\n    \"@types/lodash\": \"^4.14.118\",\n    \"@types/mongoose\": \"^5.3.17\",\n    \"@types/node\": \"^10.14.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^1.7.0\",\n    \"@typescript-eslint/parser\": \"^1.7.0\",\n    \"eslint\": \"^5.16.0\",\n    \"eslint-config-prettier\": \"^4.2.0\",\n    \"eslint-plugin-prettier\": \"^3.0.1\",\n    \"jest\": \"^24.1.0\",\n    \"nodemon\": \"^2.0.1\",\n    \"prettier\": \"^1.17.0\",\n    \"ts-jest\": \"^24.0.0\",\n    \"ts-node\": \"^7.0.1\",\n    \"tslint\": \"^5.11.0\",\n    \"typescript\": \"^3.1.3\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/santiq/bulletproof-nodejs/issues\"\n  },\n  \"homepage\": \"https://github.com/santiq/bulletproof-nodejs#readme\"\n}\n"
  },
  {
    "path": "nodejs-express-typescript/src/api/index.ts",
    "content": "import { Router } from 'express';\nimport auth from './routes/auth';\nimport user from './routes/user';\n\n// guaranteed to get dependencies\nexport default () => {\n\tconst app = Router();\n\tauth(app);\n\n\treturn app\n}"
  },
  {
    "path": "nodejs-express-typescript/src/api/middlewares/index.ts",
    "content": "import isAuth from './isAuth';\n\nexport default {\n  isAuth,\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/api/middlewares/isAuth.ts",
    "content": "import jwt from 'express-jwt';\nimport config from '../../config';\n\nconst getTokenFromHeader = req => {\n  /**\n   * @TODO Edge and Internet Explorer do some weird things with the headers\n   * So I believe that this should handle more 'edge' cases ;)\n   */\n  if (\n    (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Token') ||\n    (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer')\n  ) {\n    return req.headers.authorization.split(' ')[1];\n  }\n  return null;\n};\n\nconst isAuth = jwt({\n  secret: config.jwtSecret, // The _secret_ to sign the JWTs\n  userProperty: 'token', // Use req.token to store the JWT\n  getToken: getTokenFromHeader, // How to extract the JWT from the request\n  algorithms: ['RS256']\n});\n\nexport default isAuth;\n"
  },
  {
    "path": "nodejs-express-typescript/src/api/routes/auth.ts",
    "content": "import { Router, Request, Response, NextFunction } from 'express';\nimport { Container } from 'typedi';\nimport AuthService from '../../services/auth';\nimport { IUserInputDTO } from '../../interfaces/IUser';\nimport middlewares from '../middlewares';\nimport { celebrate, Joi } from 'celebrate';\n\nconst route = Router();\n\nexport default (app: Router) => {\n  app.use('/auth', route);\n\n  route.post(\n    '/signup',\n    celebrate({\n      body: Joi.object({\n        name: Joi.string().required(),\n        email: Joi.string().required(),\n        password: Joi.string().required(),\n      }),\n    }),\n    async (req: Request, res: Response, next: NextFunction) => {\n      const logger = Container.get('logger');\n      logger.debug('Calling Sign-Up endpoint with body: %o', req.body )\n      try {\n        const authServiceInstance = Container.get(AuthService);\n        const { user, token } = await authServiceInstance.SignUp(req.body as IUserInputDTO);\n        return res.status(201).json({ user, token });\n      } catch (e) {\n        logger.error('🔥 error: %o', e);\n        return next(e);\n      }\n    },\n  );\n\n  route.post(\n    '/signin',\n    celebrate({\n      body: Joi.object({\n        email: Joi.string().required(),\n        password: Joi.string().required(),\n      }),\n    }),\n    async (req: Request, res: Response, next: NextFunction) => {\n      const logger = Container.get('logger');\n      logger.debug('Calling Sign-In endpoint with body: %o', req.body)\n      try {\n        const { email, password } = req.body;\n        const authServiceInstance = Container.get(AuthService);\n        const { user, token } = await authServiceInstance.SignIn(email, password);\n        return res.json({ user, token }).status(200);\n      } catch (e) {\n        logger.error('🔥 error: %o',  e );\n        return next(e);\n      }\n    },\n  );\n\n  /**\n   * @TODO Let's leave this as a place holder for now\n   * The reason for a logout route could be deleting a 'push notification token'\n   * so the device stops receiving push notifications after logout.\n   *\n   * Another use case for advance/enterprise apps, you can store a record of the jwt token\n   * emitted for the session and add it to a black list.\n   * It's really annoying to develop that but if you had to, please use Redis as your data store\n   */\n  route.post('/logout', middlewares.isAuth, (req: Request, res: Response, next: NextFunction) => {\n    const logger = Container.get('logger');\n    logger.debug('Calling Sign-Out endpoint with body: %o', req.body)\n    try {\n      //@TODO AuthService.Logout(req.user) do some clever stuff\n      return res.status(200).end();\n    } catch (e) {\n      logger.error('🔥 error %o', e);\n      return next(e);\n    }\n  });\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/app.ts",
    "content": "import 'reflect-metadata'; // We need this in order to use @Decorators\nimport config from './config';\nimport express from 'express';\nimport Logger from './loaders/logger';\nasync function startServer() {\n  const app = express();\n  /**\n   * A little hack here\n   * Import/Export can only be used in 'top-level code'\n   * Well, at least in node 10 without babel and at the time of writing\n   * So we are using good old require.\n   **/\n  await require('./loaders').default({ expressApp: app });\n\n  app.listen(config.port, (err) => {\n    if (err) {\n      Logger.error(err);\n      process.exit(1);\n    }\n    Logger.info(`\n      ################################################\n      🛡️  Server listening on port: ${config.port} 🛡️ \n      ################################################\n    `);\n  });\n}\n\nstartServer();\n"
  },
  {
    "path": "nodejs-express-typescript/src/config/index.ts",
    "content": "import dotenv from 'dotenv';\n\n// Set the NODE_ENV to 'development' by default\nprocess.env.NODE_ENV = process.env.NODE_ENV || 'development';\n\nconst envFound = dotenv.config();\nif (envFound.error) {\n  // This error should crash whole process\n\n  throw new Error(\"⚠️  Couldn't find .env file  ⚠️\");\n}\n\nexport default {\n  /**\n   * Your favorite port\n   */\n  port: parseInt(process.env.PORT, 10),\n\n  /**\n   * That long string from mlab\n   */\n  databaseURL: process.env.MONGODB_URI,\n\n  /**\n   * Your secret sauce\n   */\n  jwtSecret: process.env.JWT_SECRET,\n\n  /**\n   * Used by winston logger\n   */\n  logs: {\n    level: process.env.LOG_LEVEL || 'silly',\n  },\n\n  /**\n   * Agenda.js stuff\n   */\n  agenda: {\n    dbCollection: process.env.AGENDA_DB_COLLECTION,\n    pooltime: process.env.AGENDA_POOL_TIME,\n    concurrency: parseInt(process.env.AGENDA_CONCURRENCY, 10),\n  },\n\n  /**\n   * Agendash config\n   */\n  agendash: {\n    user: 'agendash',\n    password: '123456'\n  },\n  /**\n   * API configs\n   */\n  api: {\n    prefix: '/api',\n  },\n  /**\n   * Mailgun email credentials\n   */\n  emails: {\n    apiKey: process.env.MAILGUN_API_KEY,\n    domain: process.env.MAILGUN_DOMAIN\n  }\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/interfaces/IUser.ts",
    "content": "export interface IUser {\n  _id: string;\n  name: string;\n  email: string;\n  password: string;\n  salt: string;\n}\n\nexport interface IUserInputDTO {\n  name: string;\n  email: string;\n  password: string;\n}\n"
  },
  {
    "path": "nodejs-express-typescript/src/loaders/dependencyInjector.ts",
    "content": "import { Container } from 'typedi';\nimport LoggerInstance from './logger';\nimport config from '../config';\n\nexport default ({ mongoConnection, models }: { mongoConnection; models: { name: string; model: any }[] }) => {\n  try {\n    models.forEach(m => {\n      Container.set(m.name, m.model);\n    });\n\n    Container.set('logger', LoggerInstance)\n\n    LoggerInstance.info('✌️ Agenda injected into container');\n  } catch (e) {\n    LoggerInstance.error('🔥 Error on dependency injector loader: %o', e);\n    throw e;\n  }\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/loaders/express.ts",
    "content": "import express from 'express';\nimport bodyParser from 'body-parser';\nimport cors from 'cors';\nimport routes from '../api';\nimport config from '../config';\nexport default ({ app }: { app: express.Application }) => {\n  /**\n   * Health Check endpoints\n   * @TODO Explain why they are here\n   */\n  app.get('/status', (req, res) => {\n    res.status(200).end();\n  });\n  app.head('/status', (req, res) => {\n    res.status(200).end();\n  });\n\n  // Useful if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)\n  // It shows the real origin IP in the heroku or Cloudwatch logs\n  app.enable('trust proxy');\n\n  // The magic package that prevents frontend developers going nuts\n  // Alternate description:\n  // Enable Cross Origin Resource Sharing to all origins by default\n  app.use(cors());\n\n  // Some sauce that always add since 2014\n  // \"Lets you use HTTP verbs such as PUT or DELETE in places where the client doesn't support it.\"\n  // Maybe not needed anymore ?\n\n  // Middleware that transforms the raw string of req.body into json\n  app.use(bodyParser.json());\n  // Load API routes\n  app.use(config.api.prefix, routes());\n\n  /// catch 404 and forward to error handler\n  app.use((req, res, next) => {\n    const err = new Error('Not Found');\n    err['status'] = 404;\n    next(err);\n  });\n\n  /// error handlers\n  app.use((err, req, res, next) => {\n    /**\n     * Handle 401 thrown by express-jwt library\n     */\n    if (err.name === 'UnauthorizedError') {\n      return res\n        .status(err.status)\n        .send({ message: err.message })\n        .end();\n    }\n    return next(err);\n  });\n  app.use((err, req, res, next) => {\n    res.status(err.status || 500);\n    res.json({\n      errors: {\n        message: err.message,\n      },\n    });\n  });\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/loaders/index.ts",
    "content": "import expressLoader from './express';\nimport dependencyInjectorLoader from './dependencyInjector';\nimport mongooseLoader from './mongoose';\nimport Logger from './logger';\n//We have to import at least all the events once so they can be triggered\n\nexport default async ({ expressApp }) => {\n  const mongoConnection = await mongooseLoader();\n  Logger.info('✌️ DB loaded and connected!');\n\n  /**\n   * WTF is going on here?\n   *\n   * We are injecting the mongoose models into the DI container.\n   * I know this is controversial but will provide a lot of flexibility at the time\n   * of writing unit tests, just go and check how beautiful they are!\n   */\n\n  const userModel = {\n    name: 'userModel',\n    // Notice the require syntax and the '.default'\n    model: require('../models/user').default,\n  };\n\n  // It returns the agenda instance because it's needed in the subsequent loaders\n  await dependencyInjectorLoader({\n    mongoConnection,\n    models: [\n      userModel,\n      // salaryModel,\n      // whateverModel\n    ],\n  });\n  Logger.info('✌️ Dependency Injector loaded');\n  Logger.info('✌️ Jobs loaded');\n  await expressLoader({ app: expressApp });\n  Logger.info('✌️ Express loaded');\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/loaders/logger.ts",
    "content": "import winston from 'winston';\nimport config from '../config';\n\nconst transports = [];\nif(process.env.NODE_ENV !== 'development') {\n  transports.push(\n    new winston.transports.Console()\n  )\n} else {\n  transports.push(\n    new winston.transports.Console({\n      format: winston.format.combine(\n        winston.format.cli(),\n        winston.format.splat(),\n      )\n    })\n  )\n}\n\nconst LoggerInstance = winston.createLogger({\n  level: config.logs.level,\n  levels: winston.config.npm.levels,\n  format: winston.format.combine(\n    winston.format.timestamp({\n      format: 'YYYY-MM-DD HH:mm:ss'\n    }),\n    winston.format.errors({ stack: true }),\n    winston.format.splat(),\n    winston.format.json()\n  ),\n  transports\n});\n\nexport default LoggerInstance;"
  },
  {
    "path": "nodejs-express-typescript/src/loaders/mongoose.ts",
    "content": "import mongoose from 'mongoose';\nimport config from '../config';\n\nexport default async (): Promise<any> => {\n  const connection = await mongoose.connect(config.databaseURL, { useNewUrlParser: true, useCreateIndex: true });\n  return connection.connection.db;\n};\n"
  },
  {
    "path": "nodejs-express-typescript/src/models/user.ts",
    "content": "import { IUser } from '../interfaces/IUser';\nimport mongoose from 'mongoose';\n\nconst User = new mongoose.Schema(\n  {\n    name: {\n      type: String,\n      required: [true, 'Please enter a full name'],\n      index: true,\n    },\n\n    email: {\n      type: String,\n      lowercase: true,\n      unique: true,\n      index: true,\n    },\n\n    password: String,\n\n    salt: String,\n\n    role: {\n      type: String,\n      default: 'user',\n    },\n  },\n  { timestamps: true },\n);\n\nexport default mongoose.model<IUser & mongoose.Document>('User', User);\n"
  },
  {
    "path": "nodejs-express-typescript/src/services/auth.ts",
    "content": "import { Service, Inject } from 'typedi';\nimport jwt from 'jsonwebtoken';\nimport config from '../config';\nimport argon2 from 'argon2';\nimport { randomBytes } from 'crypto';\nimport { IUser, IUserInputDTO } from '../interfaces/IUser';\n\n@Service()\nexport default class AuthService {\n  constructor(\n      @Inject('userModel') private userModel : Models.UserModel,\n      @Inject('logger') private logger,\n  ) {}\n\n  public async SignUp(userInputDTO: IUserInputDTO): Promise<{ user: IUser; token: string }> {\n    try {\n      const salt = randomBytes(32);\n      this.logger.silly('Hashing password');\n      const hashedPassword = await argon2.hash(userInputDTO.password, { salt });\n      this.logger.silly('Creating user db record');\n      const userRecord = await this.userModel.create({\n        ...userInputDTO,\n        salt: salt.toString('hex'),\n        password: hashedPassword,\n      });\n      this.logger.silly('Generating JWT');\n      const token = this.generateToken(userRecord);\n\n      if (!userRecord) {\n        throw new Error('User cannot be created');\n      }\n      this.logger.silly('Sending welcome email');\n      /**\n       * @TODO This is not the best way to deal with this\n       * There should exist a 'Mapper' layer\n       * that transforms data from layer to layer\n       * but that's too over-engineering for now\n       */\n      const user = userRecord.toObject();\n      Reflect.deleteProperty(user, 'password');\n      Reflect.deleteProperty(user, 'salt');\n      return { user, token };\n    } catch (e) {\n      this.logger.error(e);\n      throw e;\n    }\n  }\n\n  public async SignIn(email: string, password: string): Promise<{ user: IUser; token: string }> {\n    const userRecord = await this.userModel.findOne({ email });\n    if (!userRecord) {\n      throw new Error('User not registered');\n    }\n    /**\n     * We use verify from argon2 to prevent 'timing based' attacks\n     */\n    this.logger.silly('Checking password');\n    const validPassword = await argon2.verify(userRecord.password, password);\n    if (validPassword) {\n      this.logger.silly('Password is valid!');\n      this.logger.silly('Generating JWT');\n      const token = this.generateToken(userRecord);\n\n      const user = userRecord.toObject();\n      Reflect.deleteProperty(user, 'password');\n      Reflect.deleteProperty(user, 'salt');\n      /**\n       * Easy as pie, you don't need passport.js anymore :)\n       */\n      return { user, token };\n    } else {\n      throw new Error('Invalid Password');\n    }\n  }\n\n  private generateToken(user) {\n    const today = new Date();\n    const exp = new Date(today);\n    exp.setDate(today.getDate() + 60);\n\n    this.logger.silly(`Sign JWT for userId: ${user._id}`);\n    return jwt.sign(\n      {\n        _id: user._id, // We are gonna use this in the middleware 'isAuth'\n        role: user.role,\n        name: user.name,\n        exp: exp.getTime() / 1000,\n      },\n      config.jwtSecret,\n    );\n  }\n}\n"
  },
  {
    "path": "nodejs-express-typescript/src/types/express/index.d.ts",
    "content": "import { Document, Model } from 'mongoose';\nimport { IUser } from '../../interfaces/IUser';\ndeclare global {\n  namespace Express {\n    export interface Request {\n      currentUser: IUser & Document;\n    }    \n  }\n\n  namespace Models {\n    export type UserModel = Model<IUser & Document>;\n  }\n}\n"
  },
  {
    "path": "nodejs-express-typescript/tests/.gitkeep",
    "content": ""
  },
  {
    "path": "nodejs-express-typescript/tests/sample.test.ts",
    "content": "describe('Sample Test', () => {\n  it('can add 2 numbers', () => {\n    expect(1 + 2).toBe(3);\n  });\n});\n"
  },
  {
    "path": "nodejs-express-typescript/tests/services/.gitkeep",
    "content": ""
  },
  {
    "path": "nodejs-express-typescript/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2017\",\n    \"lib\": [\n      \"es2017\",\n      \"esnext.asynciterable\"\n    ],\n    \"typeRoots\": [\n      \"./node_modules/@types\",\n      \"./src/types\"\n    ],\n    \"allowSyntheticDefaultImports\": true,\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"moduleResolution\": \"node\",\n    \"module\": \"commonjs\",\n    \"pretty\": true,\n    \"sourceMap\": true,\n    \"outDir\": \"./build\",\n    \"allowJs\": true,\n    \"noEmit\": false,\n    \"esModuleInterop\": true\n  },\n  \"include\": [\n    \"./src/**/*\"\n  ],\n  \"exclude\": [\n    \"node_modules\",\n    \"tests\"\n  ]\n}"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/.gitignore",
    "content": ".idea\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/.travis.yml",
    "content": "language: node_js\n\nnode_js:\n  - \"6\"\n\nenv:\n  global:\n    - NODE_ENV=test\n    - MONGODB_URI=mongodb://localhost/service\n\nbefore_script:\n  - \"cd server\"\n  - \"npm install\"\n  - \"export DISPLAY=:99.0\"\n  - \"sh -e /etc/init.d/xvfb start\"\n\nscript:\n  - npm run coveralls\n\nafter_success:\n  - bash <(curl -s https://codecov.io/bash)\n\nservices: mongodb\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/docker-compose.yml",
    "content": "# Reverse Proxy\nnginx:\n    build: ./nginx\n    links:\n        - microservice1:microservice1\n        - microservice2:microservice2\n        - microservice3:microservice3\n    ports:\n        - \"80:80\"\n\n# NodeJS RESTful API Microservice\nmicroservice1:\n    build: ./server/dist\n    links:\n        - mongo:mongo\n    ports:\n        - \"9001:9000\"\n    environment:\n        NODE_ENV: production\n        MONGODB_URI: mongodb://mongo/service\n        IP: 0.0.0.0\n        PORT: 9000\nmicroservice2:\n    build: ./server/dist\n    links:\n        - mongo:mongo\n    ports:\n        - \"9002:9000\"\n    environment:\n        NODE_ENV: production\n        MONGODB_URI: mongodb://mongo/service\n        IP: 0.0.0.0\n        PORT: 9000\nmicroservice3:\n    build: ./server/dist\n    links:\n        - mongo:mongo\n    ports:\n        - \"9003:9000\"\n    environment:\n        NODE_ENV: production\n        MONGODB_URI: mongodb://mongo/service\n        IP: 0.0.0.0\n        PORT: 9000\n\n# MongoDB\nmongo:\n    image: mongo\n    ports:\n        - \"27017:27017\"\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/nginx/Dockerfile",
    "content": "# Set nginx base image\nFROM nginx\n\n# File Author / Maintainer\nMAINTAINER Marcin Mrotek\n\n# Copy custom configuration file from the current directory\nCOPY nginx.conf /etc/nginx/nginx.conf\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/nginx/nginx.conf",
    "content": "worker_processes 4;\n\nevents { worker_connections 1024; }\n\nhttp {\n\n\tupstream microservice {\n\t      least_conn;\n\t      server microservice1:9000 weight=10 max_fails=3 fail_timeout=30s;\n\t      server microservice2:9000 weight=10 max_fails=3 fail_timeout=30s;\n\t      server microservice3:9000 weight=10 max_fails=3 fail_timeout=30s;\n\t}\n\n\tserver {\n\t      listen 80;\n\n\t      location / {\n\t        proxy_pass http://microservice;\n\t        proxy_http_version 1.1;\n\t        proxy_set_header Upgrade $http_upgrade;\n\t        proxy_set_header Connection 'upgrade';\n\t        proxy_set_header Host $host;\n\t        proxy_cache_bypass $http_upgrade;\n\t      }\n\t}\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/.babelrc",
    "content": "{\n  \"presets\": [\"es2015\", \"stage-0\"],\n  \"plugins\": [\"transform-class-properties\"]\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/.editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/.gitignore",
    "content": ".idea\nnode_modules\ndist\ncoverage\nserver/config/.env\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/.jshintrc",
    "content": "{\n  \"expr\": true,\n  \"node\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"eqeqeq\": true,\n  \"immed\": true,\n  \"latedef\": \"nofunc\",\n  \"newcap\": true,\n  \"noarg\": true,\n  \"undef\": true,\n  \"smarttabs\": true,\n  \"asi\": true,\n  \"debug\": true\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/.jshintrc-spec",
    "content": "{\n  \"extends\": \".jshintrc\",\n  \"globals\": {\n    \"describe\": true,\n    \"it\": true,\n    \"before\": true,\n    \"beforeEach\": true,\n    \"after\": true,\n    \"afterEach\": true,\n    \"expect\": true,\n    \"assert\": true,\n    \"sinon\": true\n  }\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/Dockerfile",
    "content": "# Set the base image to Node\nFROM node\n\n# File Author / Maintainer\nMAINTAINER Marcin Mrotek\n\n# Provides cached layer for node_modules\nADD package.json /tmp/package.json\nRUN cd /tmp && npm install\nRUN mkdir -p /src && cp -a /tmp/node_modules /src/\nRUN npm install pm2 -g\n\n# Define working directory\nWORKDIR /src\nADD . /src\n\n# Expose port\nEXPOSE  9000\n\n# Run app using pm2\nCMD [\"npm\", \"run\", \"pm2\"]\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/Procfile",
    "content": "web: node index.js\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/index.js",
    "content": "'use strict';\n\n/**\n * @description Express Framework Router\n * @param Router\n */\nimport { Router } from 'express';\n\n/**\n * @description Service route Controller\n * @param ServiceController\n */\nimport * as ServiceController from './service.controller';\n\nlet router = new Router();\n\nrouter.get('/', ServiceController.index);\nrouter.get('/:id', ServiceController.show);\nrouter.post('/', ServiceController.create);\nrouter.put('/:id', ServiceController.update);\nrouter.patch('/:id', ServiceController.update);\nrouter.delete('/:id', ServiceController.destroy);\n\n/**\n * @description Configured router for Service Routes\n * @exports router\n * @default\n */\nexport default router;\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/index.spec.js",
    "content": "'use strict';\n\nlet proxyquire = require('proxyquire').noPreserveCache();\n\nconst serviceCtrlStub = {\n  index: 'serviceCtrl.index',\n  show: 'serviceCtrl.show',\n  create: 'serviceCtrl.create',\n  update: 'serviceCtrl.update',\n  destroy: 'serviceCtrl.destroy'\n};\n\nconst routerStub = {\n  get: sinon.spy(),\n  put: sinon.spy(),\n  patch: sinon.spy(),\n  post: sinon.spy(),\n  delete: sinon.spy()\n};\n\n// require the index with our stubbed out modules\nconst serviceIndex = proxyquire('./index.js', {\n  'express': {\n    Router: function() {\n      return routerStub;\n    }\n  },\n  './service.controller': serviceCtrlStub\n});\n\ndescribe('Service API Router:', function() {\n\n  describe('GET /api/services', function() {\n\n    it('should route to service.controller.index', function() {\n      expect(routerStub.get\n        .withArgs('/', 'serviceCtrl.index')\n      ).to.have.been.calledOnce;\n    });\n\n  });\n\n  describe('GET /api/services/:id', function() {\n\n    it('should route to service.controller.show', function() {\n      expect(routerStub.get\n        .withArgs('/:id', 'serviceCtrl.show')\n      ).to.have.been.calledOnce;\n    });\n\n  });\n\n  describe('POST /api/services', function() {\n\n    it('should route to service.controller.create', function() {\n      expect(routerStub.post\n        .withArgs('/', 'serviceCtrl.create')\n      ).to.have.been.calledOnce;\n    });\n\n  });\n\n  describe('PUT /api/services/:id', function() {\n\n    it('should route to service.controller.update', function() {\n      expect(routerStub.put\n        .withArgs('/:id', 'serviceCtrl.update')\n      ).to.have.been.calledOnce;\n    });\n\n  });\n\n  describe('PATCH /api/services/:id', function() {\n\n    it('should route to service.controller.update', function() {\n      expect(routerStub.patch\n        .withArgs('/:id', 'serviceCtrl.update')\n      ).to.have.been.calledOnce;\n    });\n\n  });\n\n  describe('DELETE /api/services/:id', function() {\n\n    it('should route to service.controller.destroy', function() {\n      expect(routerStub.delete\n        .withArgs('/:id', 'serviceCtrl.destroy')\n      ).to.have.been.calledOnce;\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/service.controller.js",
    "content": "/**\n * GET     /api/service              ->  index\n * POST    /api/service              ->  create\n * GET     /api/service/:id          ->  show\n * PUT     /api/service/:id          ->  update\n * PATCH   /api/service/:id          ->  update\n * DELETE  /api/service/:id          ->  destroy\n */\n\n/**\n * @description Service Model\n * @param Service\n */\nimport Service from './service.model';\n\n/**\n * @description API Response Utility functions\n * @param {Function} validationError - Check for Model validation errors\n * @param handleError - Handle errors\n * @param handleEntityNotFound - Handle Entity not found error\n * @param removeEntity - Remove entity from DB\n * @param saveUpdates - Save entity updates to DB\n * @param respondWithResult - Respond with DB results\n */\nimport {\n  validationError,\n  handleError,\n  handleEntityNotFound,\n  removeEntity,\n  saveUpdates,\n  respondWithResult\n} from '../utils';\n\n/**\n * @function index\n * @description Function that returns all allocations\n * @param {Object} req - Express Framework Request Object\n * @param {Object} res - Express Framework Response Object\n */\nfunction index(req, res) {\n  return Service.find()\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n/**\n * @function show\n * @description Function that returns single user by id provided in url\n * @param {Object} req - Express Framework Request Object\n * @param {Object} res - Express Framework Response Object\n */\nfunction show(req, res) {\n  return Service.findById(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n/**\n * @function create\n * @description Function that create user by provided request body\n * @param {Object} req - Express Framework Request Object\n * @param {Object} res - Express Framework Response Object\n */\nfunction create(req, res) {\n  return Service.create(req.body)\n    .then(respondWithResult(res, 201))\n    .catch(validationError(res));\n}\n\n/**\n * @function update\n * @description Function that update user by provided id in url and updated data in request body\n * @param {Object} req - Express Framework Request Object\n * @param {Object} res - Express Framework Response Object\n */\nfunction update(req, res) {\n  if (req.body._id) {\n    delete req.body._id;\n  }\n\n  return Service.findById(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(saveUpdates(req.body))\n    .then(respondWithResult(res))\n    .catch(validationError(res));\n}\n\n/**\n * @function destroy\n * @description Function that delete user by id provided in url\n * @param {Object} req - Express Framework Request Object\n * @param {Object} res - Express Framework Response Object\n */\nfunction destroy(req, res) {\n  return Service.findById(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(removeEntity(res))\n    .catch(handleError(res));\n}\n\nexport { index, show, create, update, destroy }\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/service.events.js",
    "content": "'use strict';\n\n/**\n * @description Events Emitter\n * @param EventEmitter\n */\nimport { EventEmitter } from 'events';\n\n/**\n * @description Service MongoDB schema\n * @param Service\n */\nimport Service from './service.model';\n\n/**\n * @description Service Events Emitter\n * @param ServiceEvents\n */\nconst ServiceEvents = new EventEmitter();\n\nServiceEvents.setMaxListeners(0);\n\n/**\n * @description Events to listen on\n * @param events\n */\nconst events = {\n  'afterCreate': 'save',\n  'afterUpdate': 'save',\n  'afterDestroy': 'remove'\n};\n\n/**\n * @description Emit correct event on hooks\n */\nfor (const e in events) {\n  const event = events[e];\n  Service.schema.post(e, emitEvent(event));\n}\n\n/**\n * @description Emit correct event\n * @function emitEvent\n * @function emitEvent\n * @param event - Event to emit\n */\nfunction emitEvent(event) {\n  return (doc, options, done) => {\n    ServiceEvents.emit(event + ':' + doc._id, doc);\n    ServiceEvents.emit(event, doc);\n    done(null);\n  }\n}\n\n/**\n * @export ServiceEvents\n * @default\n */\nexport default ServiceEvents;\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/service.integration.js",
    "content": "'use strict';\n\nimport request from 'supertest';\nimport { expect } from 'chai';\nimport Service from './service.model';\n\nlet app = require('../..');\nlet newService;\n\ndescribe('Service API:', () => {\n\n  before(done => {\n    Service.remove({})\n      .then(() => done())\n  });\n\n  describe('GET /api/services', () => {\n    let services;\n\n    beforeEach(done => {\n      request(app)\n        .get('/api/services')\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) return done(err);\n          services = res.body;\n          done();\n        });\n    });\n\n    it('should respond with JSON array', () => {\n      expect(services).to.be.instanceOf(Array);\n    });\n\n  });\n\n  describe('POST /api/services', () => {\n    beforeEach(done => {\n      request(app)\n        .post('/api/services')\n        .send({\n          name: 'Service Test'\n        })\n        .expect(201)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) return done(err);\n          newService = res.body;\n          done();\n        });\n    });\n\n    it('should respond with the newly created service', () => {\n      expect(newService).to.be.instanceOf(Object);\n      expect(newService).ownProperty('_id');\n      expect(newService._id).to.not.be.undefined;\n      expect(newService._id).to.not.be.null;\n      expect(newService).ownProperty('name');\n      expect(newService.name).to.equal('Service Test');\n      expect(newService).ownProperty('createdAt');\n      expect(newService.createdAt).to.not.be.undefined;\n      expect(newService.createdAt).to.not.be.null;\n    });\n\n  });\n\n  describe('GET /api/services/:id', () => {\n    let service;\n\n    beforeEach(done => {\n      request(app)\n        .get('/api/services/' + newService._id)\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) return done(err);\n          service = res.body;\n          done();\n        });\n    });\n\n    afterEach(() => {\n      service = {};\n    });\n\n    it('should respond with the requested service', () => {\n      expect(service).to.be.instanceOf(Object);\n      expect(service).ownProperty('_id');\n      expect(service._id).to.not.be.undefined;\n      expect(service._id).to.not.be.null;\n      expect(service).ownProperty('name');\n      expect(service.name).to.equal('Service Test');\n      expect(service).ownProperty('createdAt');\n      expect(service.createdAt).to.not.be.undefined;\n      expect(service.createdAt).to.not.be.null;\n    });\n\n  });\n\n  describe('PUT /api/services/:id', () => {\n    let updatedService;\n\n    beforeEach(done => {\n      request(app)\n        .put('/api/services/' + newService._id)\n        .send({\n\n          _id: newService._id,\n          name: 'Updated Service'\n        })\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) return done(err);\n          updatedService = res.body;\n          done();\n        });\n    });\n\n    afterEach(() => {\n      updatedService = {};\n    });\n\n    it('should respond with the updated service', () => {\n      expect(updatedService).to.be.instanceOf(Object);\n      expect(updatedService).ownProperty('_id');\n      expect(updatedService._id).to.not.be.undefined;\n      expect(updatedService._id).to.not.be.null;\n      expect(updatedService).ownProperty('name');\n      expect(updatedService.name).to.equal('Updated Service');\n      expect(updatedService).ownProperty('createdAt');\n      expect(updatedService.createdAt).to.not.be.undefined;\n      expect(updatedService.createdAt).to.not.be.null;\n      // expect(updatedService).ownProperty('updatedAt');\n      // expect(updatedService.updatedAt).to.not.be.undefined;\n      // expect(updatedService.updatedAt).to.not.be.null;\n    });\n\n  });\n\n  describe('PATCH /api/services/:id', () => {\n    let patchedService;\n\n    beforeEach(done => {\n      request(app)\n        .put('/api/services/' + newService._id)\n        .send({\n          _id: newService._id,\n          name: 'Patched Service'\n        })\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) return done(err);\n          patchedService = res.body;\n          done();\n        });\n    });\n\n    afterEach(() => {\n      patchedService = {};\n    });\n\n    it('should respond with the updated service', () => {\n      expect(patchedService).to.be.instanceOf(Object);\n      expect(patchedService).ownProperty('_id');\n      expect(patchedService._id).to.not.be.undefined;\n      expect(patchedService._id).to.not.be.null;\n      expect(patchedService).ownProperty('name');\n      expect(patchedService.name).to.equal('Patched Service');\n      expect(patchedService).ownProperty('createdAt');\n      expect(patchedService.createdAt).to.not.be.undefined;\n      expect(patchedService.createdAt).to.not.be.null;\n      // expect(patchedService).ownProperty('updatedAt');\n      // expect(patchedService.updatedAt).to.not.be.undefined;\n      // expect(patchedService.updatedAt).to.not.be.null;\n    });\n\n  });\n\n  describe('DELETE /api/services/:id', () => {\n\n    it('should respond with 204 on successful removal', done => {\n      request(app)\n        .delete('/api/services/' + newService._id)\n        .expect(204)\n        .end((err, res) => {\n          if (err) return done(err);\n          done();\n        });\n    });\n\n    it('should respond with 404 when service does not exist', done => {\n      request(app)\n        .delete('/api/services/' + newService._id)\n        .expect(404)\n        .end((err, res) => {\n          if (err) return done(err);\n          done();\n        });\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/service.model.js",
    "content": "'use strict';\n\n/**\n * @description MongoDB connector\n * @param mongoose\n */\nimport mongoose from 'mongoose';\n\n/**\n * @description Promise library\n * @param Promise\n */\nimport Promise from 'bluebird';\n\n/**\n * @description MongoDB Schema\n * @param Schema\n */\nimport { Schema } from 'mongoose';\n\n// Apply bluebird Promise as Mongoose Promise library\nmongoose.Promise = Promise;\n\n/**\n * @description Service MongoDB Schema\n * @param ServiceSchema\n * @const\n */\nconst ServiceSchema = new Schema({\n  name: {\n    type: String,\n    required: true,\n    trim: true\n  },\n  createdAt: {\n    type: Date,\n    default: Date.now\n  },\n  updatedAt: {\n    type: Date\n  }\n});\n\n/**\n * @description Virtual Method that returns service data\n */\nServiceSchema\n  .virtual('service')\n  .get(function () {\n    return {\n      'id': this._id,\n      'name': this.name\n    };\n  });\n\n/**\n * @description Validate if name field is not empty\n */\nServiceSchema\n  .path('name')\n  .validate(name => name.length, 'Name cannot be empty');\n\n/**\n * @description Validate if name is not taken\n */\nServiceSchema\n  .path('name')\n  .validate(function (name, respond) {\n    const self = this;\n    return self.constructor.findOne({ name }).exec()\n      .then(name => {\n        if (name) return respond(false);\n        return respond(true);\n      })\n  }, 'The specified name is already in use.');\n\n/**\n * @description Every update set new updatedAt date\n */\nServiceSchema\n  .post('update', function () {\n    this.update({},{\n      $set: {\n        updatedAt: new Date()\n      }\n    });\n  });\n\n/**\n * @exports serviceSchema\n * @default\n */\nexport default mongoose.model('Service', ServiceSchema);\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/service/service.socket.js",
    "content": "'use strict';\n\n/**\n * @description Service Events Emitter\n * @param ServiceEvents\n */\nimport ServiceEvents from './service.events';\n\n/**\n * @description Service Model Events to emit\n * @param events\n */\nconst events = ['save', 'remove'];\n\n/**\n * @description Broadcast events to client\n * @function register\n * @param socket - Socket library\n */\nfunction register(socket) {\n  for (let i = 0, eventsLength = events.length; i < eventsLength; i++) {\n    const event = events[i];\n    const listener = createListener('service:' + event, socket);\n\n    ServiceEvents.on(event, listener);\n    socket.on('disconnect', removeListener(event, listener));\n  }\n}\n\n/**\n * @description Emit Model event to client\n * @function createListener\n * @param event - Model event\n * @param socket - Socket library\n */\nfunction createListener(event, socket) {\n  return doc => {\n    socket.emit(event, doc);\n  };\n}\n\n/**\n * @description Remove event emitter to client\n * @function removeListener\n * @param event - Model event\n * @param listener - Socket Listener\n */\nfunction removeListener(event, listener) {\n  return () => {\n    ServiceEvents.removeListener(event, listener);\n  };\n}\n\n/**\n * @export register\n * @default\n */\nexport default register;\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/api/utils.js",
    "content": "import _ from 'lodash';\n\n/**\n * @function respondWithResult\n * @description Function that returns response with data\n * @param {Object} res - Express Framework Response Object\n * @param {Number=} statusCode - Response status code\n */\nfunction respondWithResult(res, statusCode) {\n  statusCode = statusCode || 200;\n  return entity => {\n    if (entity) {\n      return res.status(statusCode).json(entity);\n    }\n  };\n}\n\n/**\n * @function saveUpdates\n * @description Function that updates entity with new data\n * @param {Object} updates - Updated data\n */\n\nfunction saveUpdates(updates) {\n  return entity => {\n    const updated = _.merge(entity, updates);\n    return updated.save()\n      .then(updated => updated);\n  };\n}\n\n/**\n * @function removeEntity\n * @description Function that remove entity from Schema\n * @param {Object} res - Express Framework Response Object\n */\nfunction removeEntity(res) {\n  return entity => {\n    if (entity) {\n      return entity.remove()\n        .then(() => {\n          res.status(204).end();\n        });\n    }\n  };\n}\n\n/**\n * @function handleEntityNotFound\n * @description Function that handle entity not found respond\n * @param {Object} res - Express Framework Response Object\n */\nfunction handleEntityNotFound(res) {\n  return entity => {\n    if (!entity) {\n      res.status(404).end();\n      return null;\n    }\n    return entity;\n  };\n}\n\n/**\n * @function handleError\n * @description Function that returns response with error details\n * @param {Object} res - Express Framework Response Object\n * @param {Number=} statusCode - Response status code\n */\nfunction handleError(res, statusCode) {\n  statusCode = statusCode || 500;\n  return err => res.status(statusCode).send(err);\n}\n\n/**\n * @function validationError\n * @description Function that returns response with model validation error details\n * @param {Object} res - Express Framework Response Object\n * @param {Number=} statusCode - Response status code\n */\nfunction validationError(res, statusCode) {\n  statusCode = statusCode || 422;\n  return err => res.status(statusCode).json(err);\n}\n\nexport {\n  validationError,\n  handleError,\n  handleEntityNotFound,\n  removeEntity,\n  saveUpdates,\n  respondWithResult\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/app.js",
    "content": "/**\n * @description HTTP server module\n * @param http\n */\nimport http from 'http';\n\n/**\n * @description Express Framework module\n * @param express\n */\nimport express from 'express';\n\n/**\n * @description Configure env variables\n * @param config\n */\nimport dotenv from 'dotenv-safe'\ndotenv.load({\n  path: `${__dirname}/config/.env`,\n  sample: `${__dirname}/.env.example`,\n  allowEmptyValues: false\n});\n\n/**\n * @description Database config class\n * @param DBConfig\n */\nimport DBConfig from './config/db.conf';\n\n/**\n * @description Routes config class\n * @param Routes\n */\nimport { initRoutes } from './config/routes.conf';\n\n/**\n * @description IApplication config class\n * @param Routes\n */\nimport ApplicationConfig from './config/app.conf';\n\n/**\n * @description Create application with Express Framework\n * @param app\n */\nconst app = express();\n\n/**\n * @description Create application server\n * @param server\n */\nconst server = http.createServer(app);\n\n/**\n * @description Configure Database\n */\nDBConfig.init();\n\n/**\n * @description Configure Application\n */\nApplicationConfig.init(app);\n\n/**\n * @description Configure Routes\n */\ninitRoutes(app);\n\n/**\n * @function startServer\n * @description Start API Server\n */\nconst startServer = () => {\n  server.listen(process.env.PORT, process.env.IP, () => {\n    console.log('Express server listening on %s:%s in %s mode', process.env.IP, process.env.PORT, process.env.NODE_ENV);\n  });\n};\n\n/**\n * @description Starting API Server after everythin is set up\n */\nsetImmediate(startServer);\n\n/**\n * @description Application object\n * @module app\n */\nmodule.exports = app;\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/config/app.conf.js",
    "content": "import morgan from 'morgan';\nimport bodyParser from 'body-parser';\nimport contentLength from 'express-content-length-validator';\nimport helmet from 'helmet';\nimport express from 'express';\n\nexport default class ApplicationConfig {\n  static init(app) {\n    let _root = process.cwd();\n    let _nodeModules = '/node_modules/';\n\n    app.use(express.static(_root + _nodeModules));\n    app.use(bodyParser.json());\n    app.use(morgan('dev'));\n    app.use(contentLength.validateMax({max: 999}));\n    app.use(helmet());\n  }\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/config/db.conf.js",
    "content": "import mongoose from 'mongoose';\nimport bluebird from 'bluebird';\n\nmongoose.Promise = bluebird;\n\nexport default class DBConfig {\n  static init() {\n    mongoose.connect(process.env.MONGODB_URI);\n    mongoose.connection.on('error', err => {\n      console.error(`MongoDB connection error: ${err}`);\n      process.exit(-1);\n    });\n  }\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/config/routes.conf.js",
    "content": "import ServiceRoutes from '../api/service'\n\nexport function initRoutes (app) {\n  const startTime = new Date();\n\n  // Insert routes below\n  app.use('/api/services', ServiceRoutes);\n\n  app.route('/*')\n    .get((req, res) => {\n        const uptime = `${new Date() - startTime}ms`;\n        res.status(200).json({ startTime, uptime });\n      }\n    );\n\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/config/socket.conf.js",
    "content": "'use strict';\n\nimport ServiceSockets from '../api/service/service.socket';\n\n// When the user disconnects.. perform this\nfunction onDisconnect(socket) {\n}\n\n// When the user connects.. perform this\nfunction onConnect(socket) {\n  // When the client emits 'info', this listens and executes\n  socket.on('info', data => {\n    socket.log(JSON.stringify(data, null, 2));\n  });\n\n  ServiceSockets(socket);\n}\n\nfunction initSocket (socketio) {\n  socketio.on('connection', socket => {\n    socket.address = socket.request.connection.remoteAddress +\n      ':' + socket.request.connection.remotePort;\n\n    socket.connectedAt = new Date();\n\n    socket.log = (...data) => {\n      console.log(`SocketIO ${socket.nsp.name} [${socket.address}]`, ...data);\n    };\n\n    // Call onDisconnect.\n    socket.on('disconnect', () => {\n      onDisconnect(socket);\n      socket.log('DISCONNECTED');\n    });\n\n    // Call onConnect.\n    onConnect(socket);\n    socket.log('CONNECTED');\n  });\n}\n\nexport {\n  initSocket\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/gulpfile.babel.js",
    "content": "import _ from 'lodash';\nimport del from 'del';\nimport gulp from 'gulp';\nimport gulpLoadPlugins from 'gulp-load-plugins';\nimport lazypipe from 'lazypipe';\nimport nodemon from 'nodemon';\nimport runSequence from 'run-sequence';\nimport { Instrumenter } from 'isparta';\n\nlet plugins = gulpLoadPlugins();\n\nconst serverPaths = {\n  scripts: [\n    '**/!(*.spec|*.integration).js',\n    '!mocha.conf.js',\n    '!gulpfile.babel.js',\n    '!node_modules/**/*',\n    '!dist/**/*.js',\n    '!coverage/**/*',\n    '!config/local.env.sample.js'\n  ],\n  json: '**/*.json',\n  test: {\n    integration: 'api/**/*.integration.js',\n    unit: 'api/**/*.spec.js',\n    coverage: [\n      'api/**/*.js',\n      '!api/**/*.events.js',\n      '!api/**/*.socket.js'\n    ]\n  }\n};\n\nconst distPath = 'dist';\n\n/********************\n * Helper functions\n ********************/\n\nfunction onServerLog(log) {\n  console.log(plugins.util.colors.white('[') +\n    plugins.util.colors.yellow('nodemon') +\n    plugins.util.colors.white('] ') +\n    log.message);\n}\n\n/********************\n * Reusable pipelines\n ********************/\n\nlet lintServerScripts = lazypipe()\n  .pipe(plugins.jshint, './.jshintrc')\n  .pipe(plugins.jshint.reporter, 'jshint-stylish');\n\nlet lintServerTestScripts = lazypipe()\n  .pipe(plugins.jshint, './.jshintrc-spec')\n  .pipe(plugins.jshint.reporter, 'jshint-stylish');\n\nlet transpileServer = lazypipe()\n  .pipe(plugins.sourcemaps.init)\n  .pipe(plugins.babel, {\n    plugins: [\n      'transform-class-properties',\n      'transform-runtime'\n    ]\n  })\n  .pipe(plugins.sourcemaps.write, '.');\n\nlet mocha = lazypipe()\n  .pipe(plugins.mocha, {\n    reporter: 'spec',\n    timeout: 5000,\n    require: [\n      './mocha.conf'\n    ]\n  });\n\nlet istanbul = lazypipe()\n  .pipe(plugins.istanbul.writeReports)\n  .pipe(plugins.istanbulEnforcer, {\n    thresholds: {\n      global: {\n        lines: 80,\n        statements: 80,\n        branches: 80,\n        functions: 80\n      }\n    },\n    coverageDirectory: './coverage',\n    rootDirectory : ''\n  });\n\n/********************\n * Env\n ********************/\n\ngulp.task('env:test', () => {\n  plugins.env({\n    vars: { NODE_ENV: 'test' }\n  });\n});\n\ngulp.task('env:prod', () => {\n  plugins.env({\n    vars: { NODE_ENV: 'production' }\n  });\n});\n\n/********************\n * Tasks\n ********************/\n\ngulp.task('transpile:server', () => {\n  return gulp.src(_.union(serverPaths.scripts, serverPaths.json))\n    .pipe(transpileServer())\n    .pipe(gulp.dest(distPath));\n});\n\ngulp.task('lint:scripts:server', () => {\n  return gulp.src(_.union(serverPaths.scripts, _.map(serverPaths.test, blob => '!' + blob)))\n    .pipe(lintServerScripts());\n});\n\ngulp.task('lint:scripts:serverTest', () => {\n  return gulp.src(serverPaths.test)\n    .pipe(lintServerTestScripts());\n});\n\ngulp.task('jscs', () => {\n  return gulp.src(serverPaths.scripts)\n    .pipe(plugins.jscs())\n    .pipe(plugins.jscs.reporter());\n});\n\ngulp.task('start:server', () => {\n  process.env.NODE_ENV = process.env.NODE_ENV || 'development';\n  nodemon(`-w index.js index.js`)\n    .on('log', onServerLog);\n});\n\ngulp.task('start:server:prod', () => {\n  process.env.NODE_ENV = process.env.NODE_ENV || 'production';\n  nodemon(`-w ./${distPath} ./${distPath}`)\n    .on('log', onServerLog);\n});\n\ngulp.task('start:inspector', () => {\n  gulp.src([])\n    .pipe(plugins.nodeInspector());\n});\n\ngulp.task('start:server:debug', () => {\n  process.env.NODE_ENV = process.env.NODE_ENV || 'development';\n  nodemon(`-w ./ --debug-brk ./`)\n    .on('log', onServerLog);\n});\n\ngulp.task('watch', () => {\n  var testFiles = _.union(serverPaths.test.unit, serverPaths.test.integration);\n\n  plugins.livereload.listen();\n\n  plugins.watch(_.union(serverPaths.scripts, testFiles))\n    .pipe(plugins.plumber())\n    .pipe(lintServerScripts())\n    .pipe(plugins.livereload());\n\n});\n\ngulp.task('serve', cb => {\n  runSequence(\n    'lint:scripts:server',\n    'start:server',\n    'watch',\n    cb\n  );\n});\n\ngulp.task('serve:dist', cb => {\n  runSequence(\n    'clean:dist',\n    'build',\n    'start:server:prod',\n    cb\n  );\n});\n\ngulp.task('serve:debug', cb => {\n  runSequence(\n    'lint:scripts:server',\n    'start:inspector',\n    'start:server:debug',\n    'watch',\n    cb\n  );\n});\n\ngulp.task('test', cb => {\n  return runSequence('test:server', cb);\n});\n\ngulp.task('test:server', cb => {\n  runSequence(\n    'env:test',\n    'mocha:unit',\n    'mocha:integration',\n    'mocha:coverage',\n    'mocha:coveralls',\n    cb\n  );\n});\n\ngulp.task('mocha:unit', () => {\n  return gulp.src(serverPaths.test.unit)\n    .pipe(mocha());\n});\n\ngulp.task('mocha:integration', () => {\n  return gulp.src(serverPaths.test.integration)\n    .pipe(mocha());\n});\n\ngulp.task('build', cb => {\n  runSequence(\n    'clean:dist',\n    'transpile:server',\n    'copy:server',\n    cb\n  );\n});\n\ngulp.task('clean:dist', () => del([`${distPath}/!(.git*)**`], {dot: true}));\n\ngulp.task('copy:server', () => {\n  return gulp.src([\n    'package.json',\n    'Dockerfile',\n    '.env.example'\n  ], {cwdbase: true})\n    .pipe(gulp.dest(distPath));\n});\n\ngulp.task('coverage:pre', () => {\n  return gulp.src(serverPaths.test.coverage)\n    .pipe(plugins.istanbul({\n      instrumenter: Instrumenter,\n      includeUntested: true\n    }))\n    .pipe(plugins.istanbul.hookRequire());\n});\n\ngulp.task('coverage:unit', () => {\n  return gulp.src(serverPaths.test.unit)\n    .pipe(mocha())\n    .pipe(istanbul());\n});\n\ngulp.task('coverage:integration', () => {\n  return gulp.src(serverPaths.test.integration)\n    .pipe(mocha())\n    .pipe(istanbul());\n});\n\ngulp.task('mocha:coveralls', () => {\n  return gulp.src('coverage/**/lcov.info')\n    .pipe(plugins.coveralls());\n});\n\ngulp.task('mocha:coverage', cb => {\n  runSequence(\n    'coverage:pre',\n    'env:test',\n    'coverage:unit',\n    'coverage:integration',\n    cb\n  );\n});\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/index.js",
    "content": "'use strict';\n\n// Set default node environment to development\nvar env = process.env.NODE_ENV = process.env.NODE_ENV || 'development';\n\nif (env === 'development' || env === 'test') {\n  // Register the Babel require hook\n  require('babel-register');\n}\n// Export the application\nexports = module.exports = require('./app');\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/mocha.conf.js",
    "content": "'use strict';\n\n// Register the Babel require hook\nrequire('babel-core/register');\n\nvar chai = require('chai');\n\n// Load Chai assertions\nglobal.expect = chai.expect;\nglobal.assert = chai.assert;\nchai.should();\n\n// Load Sinon\nglobal.sinon = require('sinon');\n\n// Initialize Chai plugins\nchai.use(require('sinon-chai'));\nchai.use(require('chai-as-promised'));\nchai.use(require('chai-things'));\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-1/server/package.json",
    "content": "{\n  \"name\": \"nodejs-microservice-starter\",\n  \"version\": \"1.2.0\",\n  \"description\": \"NodeJS RESTful API Microservice\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"start\": \"pm2 start index.js -i 4 --name=\\\"microservice\\\" --no-daemon\",\n    \"dev\": \"gulp serve\",\n    \"dist\": \"gulp serve:dist\",\n    \"build\": \"gulp build\",\n    \"test\": \"gulp test\",\n    \"coverage\": \"gulp mocha:coverage\",\n    \"coveralls\": \"gulp mocha:coveralls\"\n  },\n  \"author\": \"Marcin Mrotek <kontakt@marcinmrotek.pl>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"autoprefixer\": \"^6.0.0\",\n    \"babel-cli\": \"^6.3.15\",\n    \"babel-core\": \"^6.6.5\",\n    \"babel-plugin-transform-class-properties\": \"^6.6.0\",\n    \"babel-plugin-transform-runtime\": \"^6.6.0\",\n    \"babel-preset-es2015\": \"^6.3.13\",\n    \"babel-preset-stage-0\": \"^6.3.13\",\n    \"babel-register\": \"^6.6.5\",\n    \"chai\": \"^3.5.0\",\n    \"chai-as-promised\": \"^5.1.0\",\n    \"chai-things\": \"^0.2.0\",\n    \"connect-livereload\": \"^0.5.3\",\n    \"coveralls\": \"^2.11.11\",\n    \"del\": \"^2.0.2\",\n    \"gulp\": \"^3.9.1\",\n    \"gulp-add-src\": \"^0.2.0\",\n    \"gulp-autoprefixer\": \"^3.1.0\",\n    \"gulp-babel\": \"^6.1.2\",\n    \"gulp-cache\": \"^0.4.2\",\n    \"gulp-concat\": \"^2.6.0\",\n    \"gulp-coveralls\": \"^0.1.4\",\n    \"gulp-env\": \"^0.4.0\",\n    \"gulp-filter\": \"^4.0.0\",\n    \"gulp-istanbul\": \"~0.10.3\",\n    \"gulp-istanbul-enforcer\": \"^1.0.3\",\n    \"gulp-jscs\": \"^3.0.2\",\n    \"gulp-jshint\": \"^2.0.0\",\n    \"gulp-livereload\": \"^3.8.0\",\n    \"gulp-load-plugins\": \"^1.0.0-rc.1\",\n    \"gulp-mocha\": \"^2.1.3\",\n    \"gulp-node-inspector\": \"^0.1.0\",\n    \"gulp-plumber\": \"^1.0.1\",\n    \"gulp-rename\": \"^1.2.2\",\n    \"gulp-rev\": \"^7.0.0\",\n    \"gulp-rev-replace\": \"^0.4.2\",\n    \"gulp-sort\": \"^2.0.0\",\n    \"gulp-sourcemaps\": \"^1.5.2\",\n    \"gulp-svgmin\": \"^1.1.2\",\n    \"gulp-uglify\": \"^1.2.0\",\n    \"gulp-useref\": \"^3.0.3\",\n    \"gulp-util\": \"^3.0.5\",\n    \"gulp-watch\": \"^4.3.5\",\n    \"isparta\": \"^4.0.0\",\n    \"istanbul\": \"^1.1.0-alpha.1\",\n    \"jshint\": \"2.9.2\",\n    \"jshint-stylish\": \"^2.2.0\",\n    \"lazypipe\": \"^1.0.1\",\n    \"mocha\": \"^2.5.3\",\n    \"nodemon\": \"^1.8.1\",\n    \"proxyquire\": \"^1.7.9\",\n    \"run-sequence\": \"^1.1.0\",\n    \"sinon\": \"^1.17.4\",\n    \"sinon-chai\": \"^2.8.0\",\n    \"supertest\": \"^1.2.0\"\n  },\n  \"dependencies\": {\n    \"bluebird\": \"^3.4.1\",\n    \"body-parser\": \"^1.15.2\",\n    \"dotenv-safe\": \"^2.3.1\",\n    \"express\": \"^4.14.0\",\n    \"express-content-length-validator\": \"^1.0.0\",\n    \"helmet\": \"^2.1.1\",\n    \"lodash\": \"^4.13.1\",\n    \"mongoose\": \"^4.5.2\",\n    \"morgan\": \"^1.7.0\",\n    \"pm2\": \"^1.1.3\"\n  }\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/.gitignore",
    "content": "\nnode/node_modules\n.DS_Store\n\nnode/npm-debug.log\n.DS_Store\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/docker-compose.yml",
    "content": "nginx:\n    build: ./nginx\n    links:\n        - node1:node1\n        - node2:node2\n        - node3:node3\n    ports:\n        - \"80:80\"\nnode1:\n    build: ./node\n    links:\n        - redis\n    ports:\n        - \"8080\"\nnode2:\n    build: ./node\n    links:\n        - redis\n    ports:\n        - \"8080\"\nnode3:\n    build: ./node\n    links:\n        - redis\n    ports:\n        - \"8080\"\nredis:\n    image: redis\n    ports:\n        - \"6379\""
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/nginx/Dockerfile",
    "content": "# Set nginx base image\nFROM nginx\n\n# File Author / Maintainer\nMAINTAINER Anand Mani Sankar\n\n# Copy custom configuration file from the current directory\nCOPY nginx.conf /etc/nginx/nginx.conf\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/nginx/Dockerfile_custom",
    "content": "# Set the base image to Ubuntu\nFROM ubuntu\n\n# File Author / Maintainer\nMAINTAINER Anand Mani Sankar\n\n# Install Nginx\n\n# Add application repository URL to the default sources\n# RUN echo \"deb http://archive.ubuntu.com/ubuntu/ raring main universe\" >> /etc/apt/sources.list\n\n# Update the repository\nRUN apt-get update\n\n# Install necessary tools\nRUN apt-get install -y nano wget dialog net-tools\n\n# Download and Install Nginx\nRUN apt-get install -y nginx  \n\n# Remove the default Nginx configuration file\nRUN rm -v /etc/nginx/nginx.conf\n\n# Copy a configuration file from the current directory\nADD nginx.conf /etc/nginx/\n\n# Append \"daemon off;\" to the configuration file\nRUN echo \"daemon off;\" >> /etc/nginx/nginx.conf\n\n# Expose ports\nEXPOSE 80\n\n# Set the default command to execute when creating a new container\nCMD service nginx start"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/nginx/nginx.conf",
    "content": "worker_processes 4;\n\nevents { worker_connections 1024; }\n\nhttp {\n\n\tupstream node-app {\n\t      least_conn;\n\t      server node1:8080 weight=10 max_fails=3 fail_timeout=30s;\n\t      server node2:8080 weight=10 max_fails=3 fail_timeout=30s;\n\t      server node3:8080 weight=10 max_fails=3 fail_timeout=30s;\n\t}\n\t \n\tserver {\n\t      listen 80;\n\t \n\t      location / {\n\t        proxy_pass http://node-app;\n\t        proxy_http_version 1.1;\n\t        proxy_set_header Upgrade $http_upgrade;\n\t        proxy_set_header Connection 'upgrade';\n\t        proxy_set_header Host $host;\n\t        proxy_cache_bypass $http_upgrade;\n\t      }\n\t}\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/node/Dockerfile",
    "content": "# Set the base image to Ubuntu\nFROM    ubuntu:trusty\n\n# File Author / Maintainer\nMAINTAINER Anand Mani Sankar\n\n# Install Node.js and other dependencies\nRUN apt-get update && \\\n    apt-get -y install curl && \\\n    curl -sL https://deb.nodesource.com/setup | sudo bash - && \\\n    apt-get -y install python build-essential nodejs\n\n# Install nodemon\nRUN npm install -g nodemon\n\n# Provides cached layer for node_modules\nADD package.json /tmp/package.json\nRUN cd /tmp && npm install\nRUN mkdir -p /src && cp -a /tmp/node_modules /src/\n\n# Define working directory\nWORKDIR /src\nADD . /src\n\n# Expose port\nEXPOSE  8080\n\n# Run app using nodemon\nCMD [\"nodemon\", \"/src/index.js\"]\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/node/index.js",
    "content": "var express = require('express'),\n    http = require('http'),\n    redis = require('redis');\n\nvar app = express();\n\nconsole.log(process.env.REDIS_PORT_6379_TCP_ADDR + ':' + process.env.REDIS_PORT_6379_TCP_PORT);\n\n// APPROACH 1: Using environment variables created by Docker\n// var client = redis.createClient(\n// \tprocess.env.REDIS_PORT_6379_TCP_PORT,\n//   \tprocess.env.REDIS_PORT_6379_TCP_ADDR\n// );\n\n// APPROACH 2: Using host entries created by Docker in /etc/hosts (RECOMMENDED)\nvar client = redis.createClient('6379', 'redis');\n\n\napp.get('/', function(req, res, next) {\n  client.incr('counter', function(err, counter) {\n    if(err) return next(err);\n    res.send('This page has been viewed ' + counter + ' times!');\n  });\n});\n\nhttp.createServer(app).listen(process.env.PORT || 8080, function() {\n  console.log('Listening on port ' + (process.env.PORT || 8080));\n});"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/node/package.json",
    "content": "{\n  \"name\": \"node\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"author\": \"Anand Mani Sankar\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"express\": \"^4.12.3\",\n    \"hiredis\": \"^0.2.0\",\n    \"mocha\": \"^2.2.1\",\n    \"redis\": \"^0.12.1\"\n  }\n}\n"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/node/test/dummyTest.js",
    "content": "var assert = require(\"assert\");\r\n\r\ndescribe('Dummy Test', function(){\r\n    it('should pass', function(){\r\n      assert.ok(true, \"It is true!\");\r\n    });\r\n});"
  },
  {
    "path": "nodejs-microservice-using-docker-Part-2/redis/Dockerfile",
    "content": "# Set the base image to Ubuntu\nFROM        ubuntu\n\n# File Author / Maintainer\nMAINTAINER Anand Mani Sankar\n\n# Update the repository and install Redis Server\nRUN         apt-get update && apt-get install -y redis-server\n\n# Expose Redis port 6379\nEXPOSE      6379\n\n# Run Redis Server\nENTRYPOINT  [\"/usr/bin/redis-server\"]"
  }
]