Repository: tkssharma/nodejs-microservices-patterns Branch: master Commit: 2170453c4faf Files: 544 Total size: 623.6 KB Directory structure: gitextract_2afopmxn/ ├── README.md ├── api-gateway-and-service-doscovery/ │ ├── .gitignore │ ├── README.md │ ├── ServicesSetup.sh │ ├── ServicesStart.sh │ ├── api-gateway/ │ │ ├── Dockerbuild.sh │ │ ├── Dockerfile │ │ ├── api/ │ │ │ ├── account/ │ │ │ │ ├── login.js │ │ │ │ └── signup.js │ │ │ └── crm/ │ │ │ └── orders/ │ │ │ └── orders.js │ │ ├── api-gateway.js │ │ ├── config.js │ │ ├── config.json │ │ ├── package.json │ │ ├── server.js │ │ └── services-helper.js │ ├── service-log/ │ │ ├── Dockerbuild.sh │ │ ├── Dockerfile │ │ ├── config.js │ │ ├── config.json │ │ ├── log.js │ │ ├── package.json │ │ └── server.js │ ├── service-login/ │ │ ├── Dockerbuild.sh │ │ ├── Dockerfile │ │ ├── config.js │ │ ├── config.json │ │ ├── login.js │ │ ├── package.json │ │ └── server.js │ ├── service-orders/ │ │ ├── Dockerbuild.sh │ │ ├── Dockerfile │ │ ├── config.js │ │ ├── config.json │ │ ├── orders.js │ │ ├── package.json │ │ └── server.js │ └── service-signup/ │ ├── Dockerbuild.sh │ ├── Dockerfile │ ├── config.js │ ├── config.json │ ├── package.json │ ├── server.js │ └── signup.js ├── dockerized-containers/ │ ├── .eslintrc.js │ ├── .gitignore │ ├── .travis.yml │ ├── README.md │ ├── docker-compose.yml │ ├── e-Commerce-Admin/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app/ │ │ │ ├── config/ │ │ │ │ ├── email.ts │ │ │ │ └── environments/ │ │ │ │ ├── dev.ts │ │ │ │ ├── qa.ts │ │ │ │ └── test.ts │ │ │ ├── controller/ │ │ │ │ └── UserController.ts │ │ │ ├── events/ │ │ │ │ └── notification.ts │ │ │ ├── global/ │ │ │ │ └── templates/ │ │ │ │ ├── emails/ │ │ │ │ │ ├── password-reset-email/ │ │ │ │ │ │ ├── html.pug │ │ │ │ │ │ └── style.css │ │ │ │ │ └── welcome-email/ │ │ │ │ │ ├── html.pug │ │ │ │ │ └── style.css │ │ │ │ └── response/ │ │ │ │ └── index.ts │ │ │ ├── helper/ │ │ │ │ ├── bcrypt.ts │ │ │ │ ├── email.ts │ │ │ │ ├── errorHandler.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── responseTemplate.ts │ │ │ │ └── twillo.ts │ │ │ ├── lib/ │ │ │ │ ├── logger.ts │ │ │ │ ├── mongoose.ts │ │ │ │ └── requestValidator.ts │ │ │ ├── middleware/ │ │ │ │ ├── authMiddleware.ts │ │ │ │ └── requestValidator.ts │ │ │ ├── models/ │ │ │ │ ├── plugin/ │ │ │ │ │ └── plugin.ts │ │ │ │ └── user.ts │ │ │ ├── routes/ │ │ │ │ ├── defaultRoutes.ts │ │ │ │ ├── provider/ │ │ │ │ │ ├── Facebook.ts │ │ │ │ │ ├── Google.ts │ │ │ │ │ ├── Linkedin.ts │ │ │ │ │ ├── Locale.ts │ │ │ │ │ └── Twitter.ts │ │ │ │ ├── routes.ts │ │ │ │ └── userRoutes.ts │ │ │ ├── routes.ts │ │ │ ├── seed/ │ │ │ │ ├── seedUsers.ts │ │ │ │ └── seedVehicle.ts │ │ │ ├── transformer/ │ │ │ │ └── userTransformer.ts │ │ │ └── types/ │ │ │ ├── global.d.ts │ │ │ └── vendor.d.ts │ │ ├── env.sh │ │ ├── express.ts │ │ ├── package.json │ │ ├── public/ │ │ │ ├── javascripts/ │ │ │ │ └── script.js │ │ │ └── style.scss │ │ ├── server.ts │ │ ├── tsconfig.json │ │ ├── tslint.json │ │ └── uploads/ │ │ ├── documents/ │ │ │ └── .gitkeep │ │ └── profile/ │ │ └── .gitkeep │ ├── e-Commerce-Auth/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app/ │ │ │ ├── config/ │ │ │ │ ├── email.ts │ │ │ │ └── environments/ │ │ │ │ ├── dev.ts │ │ │ │ ├── qa.ts │ │ │ │ └── test.ts │ │ │ ├── controller/ │ │ │ │ └── UserController.ts │ │ │ ├── events/ │ │ │ │ └── notification.ts │ │ │ ├── global/ │ │ │ │ └── templates/ │ │ │ │ ├── emails/ │ │ │ │ │ ├── password-reset-email/ │ │ │ │ │ │ ├── html.pug │ │ │ │ │ │ └── style.css │ │ │ │ │ └── welcome-email/ │ │ │ │ │ ├── html.pug │ │ │ │ │ └── style.css │ │ │ │ └── response/ │ │ │ │ └── index.ts │ │ │ ├── helper/ │ │ │ │ ├── bcrypt.ts │ │ │ │ ├── email.ts │ │ │ │ ├── errorHandler.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── responseTemplate.ts │ │ │ │ └── twillo.ts │ │ │ ├── lib/ │ │ │ │ ├── logger.ts │ │ │ │ ├── mongoose.ts │ │ │ │ └── requestValidator.ts │ │ │ ├── middleware/ │ │ │ │ ├── authMiddleware.ts │ │ │ │ └── requestValidator.ts │ │ │ ├── models/ │ │ │ │ ├── plugin/ │ │ │ │ │ └── plugin.ts │ │ │ │ └── user.ts │ │ │ ├── routes/ │ │ │ │ ├── defaultRoutes.ts │ │ │ │ ├── provider/ │ │ │ │ │ ├── Facebook.ts │ │ │ │ │ ├── Google.ts │ │ │ │ │ ├── Linkedin.ts │ │ │ │ │ ├── Locale.ts │ │ │ │ │ └── Twitter.ts │ │ │ │ ├── routes.ts │ │ │ │ └── userRoutes.ts │ │ │ ├── routes.ts │ │ │ ├── seed/ │ │ │ │ ├── seedUsers.ts │ │ │ │ └── seedVehicle.ts │ │ │ ├── transformer/ │ │ │ │ └── userTransformer.ts │ │ │ └── types/ │ │ │ ├── global.d.ts │ │ │ └── vendor.d.ts │ │ ├── env.sh │ │ ├── express.ts │ │ ├── package.json │ │ ├── public/ │ │ │ ├── javascripts/ │ │ │ │ └── script.js │ │ │ └── style.scss │ │ ├── server.ts │ │ ├── tsconfig.json │ │ ├── tslint.json │ │ └── uploads/ │ │ ├── documents/ │ │ │ └── .gitkeep │ │ └── profile/ │ │ └── .gitkeep │ ├── e-Commerce-Cart/ │ │ ├── .sequelizerc │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app/ │ │ │ ├── config/ │ │ │ │ └── environments/ │ │ │ │ ├── dev.ts │ │ │ │ ├── qa.ts │ │ │ │ └── test.ts │ │ │ ├── events/ │ │ │ │ └── processEvent.ts │ │ │ ├── helper/ │ │ │ │ ├── errorHandler.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── logger.ts │ │ │ │ └── responseTemplate.ts │ │ │ ├── lib/ │ │ │ │ ├── logger.ts │ │ │ │ ├── mysql.ts │ │ │ │ └── requestValidator.ts │ │ │ ├── middleware/ │ │ │ │ └── requestValidator.ts │ │ │ ├── models/ │ │ │ │ └── data/ │ │ │ │ └── cart.ts │ │ │ ├── routes/ │ │ │ │ └── defaultRoutes.ts │ │ │ ├── routes.ts │ │ │ └── types/ │ │ │ ├── global.d.ts │ │ │ └── vendor.d.ts │ │ ├── config/ │ │ │ └── config.js │ │ ├── env.sh │ │ ├── express.ts │ │ ├── mysql/ │ │ │ └── schema.sql │ │ ├── package.json │ │ ├── public/ │ │ │ ├── javascripts/ │ │ │ │ └── script.js │ │ │ └── style.scss │ │ ├── server.ts │ │ ├── tsconfig.json │ │ ├── tslint.json │ │ └── uploads/ │ │ ├── documents/ │ │ │ └── .gitkeep │ │ └── profile/ │ │ └── .gitkeep │ ├── e-Commerce-Client/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── env.sh │ │ ├── firebase.json │ │ ├── package.json │ │ ├── public/ │ │ │ ├── index.html │ │ │ ├── manifest.json │ │ │ └── normalize.css │ │ └── src/ │ │ ├── api/ │ │ │ └── index.js │ │ ├── components/ │ │ │ ├── App/ │ │ │ │ └── index.js │ │ │ ├── Checkbox/ │ │ │ │ └── index.js │ │ │ ├── FloatCart/ │ │ │ │ ├── CartProduct/ │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ └── style.scss │ │ │ ├── Selectbox/ │ │ │ │ └── index.js │ │ │ ├── Shelf/ │ │ │ │ ├── Filter/ │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.scss │ │ │ │ ├── ProductList/ │ │ │ │ │ ├── Product/ │ │ │ │ │ │ └── index.js │ │ │ │ │ └── index.js │ │ │ │ ├── ShelfHeader/ │ │ │ │ │ └── index.js │ │ │ │ ├── Sort/ │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ └── style.scss │ │ │ ├── Spinner/ │ │ │ │ ├── index.js │ │ │ │ └── style.scss │ │ │ └── Thumb/ │ │ │ └── index.js │ │ ├── config/ │ │ │ ├── index.js │ │ │ └── server.js │ │ ├── index.js │ │ ├── index.scss │ │ ├── layout/ │ │ │ ├── Auth.js │ │ │ └── Public.js │ │ ├── services/ │ │ │ ├── auth/ │ │ │ │ ├── Login.js │ │ │ │ ├── Logout.js │ │ │ │ ├── Register.js │ │ │ │ ├── ResetPassword.js │ │ │ │ ├── ValidateToken.js │ │ │ │ ├── action.js │ │ │ │ ├── actionTypes.js │ │ │ │ ├── auth.scss │ │ │ │ └── reducer.js │ │ │ ├── cart/ │ │ │ │ ├── actionTypes.js │ │ │ │ ├── actions.js │ │ │ │ └── reducer.js │ │ │ ├── filters/ │ │ │ │ ├── actionTypes.js │ │ │ │ ├── actions.js │ │ │ │ └── reducer.js │ │ │ ├── reducers.js │ │ │ ├── shelf/ │ │ │ │ ├── actionTypes.js │ │ │ │ ├── actions.js │ │ │ │ └── reducer.js │ │ │ ├── sort/ │ │ │ │ ├── actionTypes.js │ │ │ │ ├── actions.js │ │ │ │ └── reducer.js │ │ │ ├── store.js │ │ │ ├── total/ │ │ │ │ ├── actionTypes.js │ │ │ │ ├── actions.js │ │ │ │ └── reducer.js │ │ │ └── util.js │ │ ├── setupTests.js │ │ └── util/ │ │ ├── helper/ │ │ │ └── index.js │ │ └── middleware/ │ │ ├── auth.js │ │ └── index.js │ └── proxy/ │ ├── default.conf │ ├── hosts │ └── ssl/ │ ├── pac.crt │ └── pac.key ├── event-driven-microservices-docker/ │ ├── .githooks/ │ │ ├── pre-commit │ │ ├── pre-commit.d/ │ │ │ ├── articles-management-service │ │ │ ├── events-management-service │ │ │ ├── notification-service │ │ │ └── user-management-service │ │ ├── pre-push │ │ └── pre-push.d/ │ │ ├── articles-management-service │ │ ├── events-management-service │ │ ├── notification-service │ │ └── user-management-service │ ├── .gitignore │ ├── docker-compose.yml │ ├── run_all_tests │ └── services/ │ ├── articles-management/ │ │ ├── .dockerignore │ │ ├── .eslintignore │ │ ├── .eslintrc.yml │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app.js │ │ │ ├── controllers/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── article.controller.js │ │ │ │ └── article.controller.js │ │ │ ├── environment/ │ │ │ │ └── config.js │ │ │ ├── message-bus/ │ │ │ │ └── send/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── article.added.js │ │ │ │ └── article.added.js │ │ │ ├── middlewares/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── jwt.js │ │ │ │ └── jwt.js │ │ │ ├── models/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── article.model.js │ │ │ │ └── article.model.js │ │ │ ├── routes/ │ │ │ │ └── article.routes.js │ │ │ └── server.js │ │ └── tests/ │ │ └── unit/ │ │ ├── __snapshots__/ │ │ │ └── article.added.message.send.test.js.snap │ │ ├── app.test.js │ │ ├── article.added.message.send.test.js │ │ ├── article.controller.test.js │ │ ├── article.model.test.js │ │ ├── article.routes.test.js │ │ ├── config.test.js │ │ └── server.test.js │ ├── authentication/ │ │ ├── .dockerignore │ │ ├── .eslintrc.yml │ │ ├── .gitignore │ │ ├── .gitkeep │ │ ├── .snyk │ │ ├── Dockerfile │ │ ├── package.json │ │ └── src/ │ │ ├── app.js │ │ ├── controllers/ │ │ │ └── auth.controller.js │ │ ├── environment/ │ │ │ └── config.js │ │ ├── message-bus/ │ │ │ └── recieve/ │ │ │ └── user.added.js │ │ ├── models/ │ │ │ └── auth.model.js │ │ ├── routes/ │ │ │ └── auth.routes.js │ │ └── server.js │ ├── events-management/ │ │ ├── .dockerignore │ │ ├── .eslintrc.yml │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app.js │ │ │ ├── controllers/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── event.controller.js │ │ │ │ └── event.controller.js │ │ │ ├── environment/ │ │ │ │ └── config.js │ │ │ ├── middlewares/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── jwt.js │ │ │ │ └── jwt.js │ │ │ ├── models/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── event.model.js │ │ │ │ └── event.model.js │ │ │ ├── routes/ │ │ │ │ └── event.routes.js │ │ │ └── server.js │ │ └── tests/ │ │ └── unit/ │ │ ├── app.test.js │ │ ├── config.test.js │ │ ├── event.controller.test.js │ │ ├── event.model.test.js │ │ ├── event.routes.test.js │ │ └── server.test.js │ ├── media-management/ │ │ └── .gitkeep │ ├── notification/ │ │ ├── .eslintrc.yml │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── __mocks__/ │ │ │ ├── amqp-ts-async.js │ │ │ ├── koa.js │ │ │ ├── nodemailer.js │ │ │ └── winston.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── environment/ │ │ │ │ └── config.js │ │ │ ├── message-controllers/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── articles.js │ │ │ │ └── articles.js │ │ │ ├── modules/ │ │ │ │ └── email/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ ├── email.js │ │ │ │ │ └── email.templates.js │ │ │ │ ├── email.js │ │ │ │ └── email.templates.js │ │ │ ├── server.js │ │ │ └── subscriptions/ │ │ │ ├── __mocks__/ │ │ │ │ └── article.added.js │ │ │ └── article.added.js │ │ └── tests/ │ │ └── unit/ │ │ ├── __snapshots__/ │ │ │ ├── config.test.js.snap │ │ │ ├── email.templates.test.js.snap │ │ │ └── email.test.js.snap │ │ ├── article.added.subscription.test.js │ │ ├── article.message.controller.test.js │ │ ├── config.test.js │ │ ├── email.templates.test.js │ │ ├── email.test.js │ │ └── server.test.js │ ├── search/ │ │ └── .gitkeep │ └── user-management/ │ ├── .dockerignore │ ├── .eslintrc.yml │ ├── .gitignore │ ├── .gitkeep │ ├── Dockerfile │ ├── __mocks__/ │ │ ├── amqp-ts-async.js │ │ └── winston.js │ ├── package.json │ ├── src/ │ │ ├── app.js │ │ ├── controllers/ │ │ │ ├── __mocks__/ │ │ │ │ └── user.controller.js │ │ │ └── user.controller.js │ │ ├── environment/ │ │ │ └── config.js │ │ ├── message-bus/ │ │ │ └── send/ │ │ │ └── user.added.js │ │ ├── middlewares/ │ │ │ ├── __mocks__/ │ │ │ │ └── jwt.js │ │ │ └── jwt.js │ │ ├── models/ │ │ │ ├── __mocks__/ │ │ │ │ └── user.model.js │ │ │ └── user.model.js │ │ ├── routes/ │ │ │ └── user.routes.js │ │ └── server.js │ └── tests/ │ └── unit/ │ ├── __snapshots__/ │ │ ├── user.added.message.send.test.js.snap │ │ └── user.controller.test.js.snap │ ├── app.test.js │ ├── config.test.js │ ├── server.test.js │ ├── user.added.message.send.test.js │ ├── user.controller.test.js │ ├── user.model.test.js │ └── user.routes.test.js ├── node js-with-serverless/ │ ├── .gitignore │ ├── README.md │ ├── functions/ │ │ ├── delete_item.ts │ │ ├── edit_item.ts │ │ ├── read_all.ts │ │ ├── read_single_item.ts │ │ └── write_item.ts │ ├── models/ │ │ └── table_schema.ts │ ├── package.json │ ├── serverless.yml │ └── shared/ │ ├── create_dynamo.ts │ └── update_dynamo.ts ├── node-js-lambda-sqs-serverless/ │ ├── .gitignore │ ├── README.md │ ├── data.json │ ├── db.js │ ├── handler.js │ ├── models/ │ │ └── note.js │ ├── package.json │ ├── serverless.yml │ └── sqs.js ├── node-microservice-starter/ │ ├── .dockerignore │ ├── .editorconfig │ ├── .gitattributes │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yml │ ├── nginx/ │ │ ├── Dockerfile │ │ └── nginx.conf │ └── users/ │ ├── .eslintrc.js │ ├── .prettierrc │ ├── Dockerfile │ ├── README.md │ ├── nest-cli.json │ ├── package.json │ ├── src/ │ │ ├── app.controller.spec.ts │ │ ├── app.controller.ts │ │ ├── app.module.ts │ │ ├── app.service.ts │ │ └── main.ts │ ├── test/ │ │ ├── app.e2e-spec.ts │ │ └── jest-e2e.json │ ├── tsconfig.build.json │ └── tsconfig.json ├── nodejs-cqrs-pattern/ │ ├── .dockerignore │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── config.ts │ ├── docker-compose.yml │ ├── docs/ │ │ └── README.md │ ├── githooks/ │ │ └── README.md │ ├── nest-cli.json │ ├── nodemon-debug.json │ ├── nodemon.json │ ├── package.json │ ├── scripts/ │ │ ├── down.sh │ │ └── up.sh │ ├── src/ │ │ ├── app.module.ts │ │ ├── core/ │ │ │ └── event-store/ │ │ │ ├── event-store.class.ts │ │ │ ├── event-store.interface.ts │ │ │ ├── event-store.module.ts │ │ │ ├── event-store.provider.ts │ │ │ └── event-store.ts │ │ ├── main.ts │ │ └── users/ │ │ ├── commands/ │ │ │ ├── handlers/ │ │ │ │ ├── create-user.handler.ts │ │ │ │ ├── delete-user.handler.ts │ │ │ │ ├── index.ts │ │ │ │ ├── update-user.handler.ts │ │ │ │ └── welcome-user.handler.ts │ │ │ └── impl/ │ │ │ ├── create-user.command.ts │ │ │ ├── delete-user.command.ts │ │ │ ├── update-user.command.ts │ │ │ └── welcome-user.command.ts │ │ ├── controllers/ │ │ │ ├── users.controller.spec.ts │ │ │ └── users.controller.ts │ │ ├── dtos/ │ │ │ └── users.dto.ts │ │ ├── events/ │ │ │ ├── handlers/ │ │ │ │ ├── index.ts │ │ │ │ ├── user-created.handler.ts │ │ │ │ ├── user-deleted.handler.ts │ │ │ │ ├── user-updated.handler.ts │ │ │ │ └── user-welcomed.handler.ts │ │ │ └── impl/ │ │ │ ├── user-created.event.ts │ │ │ ├── user-deleted.event.ts │ │ │ ├── user-updated.event.ts │ │ │ └── user-welcomed.event.ts │ │ ├── models/ │ │ │ └── user.model.ts │ │ ├── repository/ │ │ │ └── user.repository.ts │ │ ├── sagas/ │ │ │ └── users.sagas.ts │ │ ├── services/ │ │ │ └── users.service.ts │ │ └── users.module.ts │ ├── test/ │ │ ├── app.e2e-spec.ts │ │ └── jest-e2e.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── nodejs-express-typescript/ │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc.json │ ├── LICENSE │ ├── Procfile │ ├── README.md │ ├── jest.config.js │ ├── nodemon.json │ ├── package.json │ ├── src/ │ │ ├── api/ │ │ │ ├── index.ts │ │ │ ├── middlewares/ │ │ │ │ ├── index.ts │ │ │ │ └── isAuth.ts │ │ │ └── routes/ │ │ │ └── auth.ts │ │ ├── app.ts │ │ ├── config/ │ │ │ └── index.ts │ │ ├── interfaces/ │ │ │ └── IUser.ts │ │ ├── loaders/ │ │ │ ├── dependencyInjector.ts │ │ │ ├── express.ts │ │ │ ├── index.ts │ │ │ ├── logger.ts │ │ │ └── mongoose.ts │ │ ├── models/ │ │ │ └── user.ts │ │ ├── services/ │ │ │ └── auth.ts │ │ └── types/ │ │ └── express/ │ │ └── index.d.ts │ ├── tests/ │ │ ├── .gitkeep │ │ ├── sample.test.ts │ │ └── services/ │ │ └── .gitkeep │ └── tsconfig.json ├── nodejs-microservice-using-docker-Part-1/ │ ├── .gitignore │ ├── .travis.yml │ ├── docker-compose.yml │ ├── nginx/ │ │ ├── Dockerfile │ │ └── nginx.conf │ └── server/ │ ├── .babelrc │ ├── .editorconfig │ ├── .gitignore │ ├── .jshintrc │ ├── .jshintrc-spec │ ├── Dockerfile │ ├── Procfile │ ├── api/ │ │ ├── service/ │ │ │ ├── index.js │ │ │ ├── index.spec.js │ │ │ ├── service.controller.js │ │ │ ├── service.events.js │ │ │ ├── service.integration.js │ │ │ ├── service.model.js │ │ │ └── service.socket.js │ │ └── utils.js │ ├── app.js │ ├── config/ │ │ ├── app.conf.js │ │ ├── db.conf.js │ │ ├── routes.conf.js │ │ └── socket.conf.js │ ├── gulpfile.babel.js │ ├── index.js │ ├── mocha.conf.js │ └── package.json └── nodejs-microservice-using-docker-Part-2/ ├── .gitignore ├── docker-compose.yml ├── nginx/ │ ├── Dockerfile │ ├── Dockerfile_custom │ └── nginx.conf ├── node/ │ ├── Dockerfile │ ├── index.js │ ├── package.json │ └── test/ │ └── dummyTest.js └── redis/ └── Dockerfile ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # nodejs-microservces-patterns nodejs-microservces-patterns - Simple Microservices Demo - Simple Auth and Autnz setup - CQRS Pattern - Event Driven Design Pattern ### Different examples for understanding node js with microservoces Patterns #### https://www.youtube.com/watch?v=_pO0sDeQrp0&list=PLIGDNOJWiL182j1bD_nQm-SxARR5s977O&ab_channel=CodeLabs ================================================ FILE: api-gateway-and-service-doscovery/.gitignore ================================================ node_modules docs node/node_modules .DS_Store node/npm-debug.log .DS_Store ================================================ FILE: api-gateway-and-service-doscovery/README.md ================================================ #What is this? This 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. ![ScreenShot](https://raw.github.com/alchimya/micro-node-api-gateway/master/Microservices_Architecture.png) Actually, this project can be described as a complete Microservices Architecture containing four different microservices accessible via Api Gateway and discovered with a Service Registry. #How to setup and configure To setup the project, it is enough to launch the the bash script ServicesSetup.sh
The configuration it is a bit tedious but it is very easy. In order you need to open all the config.json file that you will find in to each project folder (services and api-gateway) and setup the MondoDB configuration within the serviceRegistry object: ```javascript "serviceRegistry":{ "watchDog":{ "isEnabled":false, "timer":30000 }, "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } ``` A more dtailed description of the configuration is reported in to the section at the bottom of this document. #How to use To start all services you must launch the bash script ServicesStart.sh. This script will provide to launch five differente clustered instances of a Node server as reported below:
Service |Port | Service Route | Api Gateway Ruote (8080) ----------------|------------|---------------|------------------------- service-login | 8081 | /api/login | /api/account/login service-signup | 8082 | /api/signup | /api/account/signup service-orders | 8084 | /api/orders | /api/crm/orders service-log | 8084 | /api/log | ----- api-gateway | 8080 | ---- | -----
For 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. #Api Gateway Configuraiton Here, a detailed description of the config.json file for the Pai Gateway ```javascript { "server":{ "id":"MicroNodeApiGateway", "port":8080, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"login", "path":"api/account", "route":"account/login"}, {"name":"signup", "path":"api/account", "route":"account/signup"}, {"name":"orders", "path":"api/crm/orders", "route":"crm/orders"} ] }, "services":[ {"name":"ServiceLog", "endpointId":"log"}, {"name":"ServiceLogin", "endpointId":"login"}, {"name":"ServiceSignup", "endpointId":"signup"}, {"name":"ServiceOrders", "endpointId":"orders"} ], "serviceRegistry":{ "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } } ``` where: - server.id: it is a key to identify the microservice - server.port: it is the port where the microservice is listen to - server,isCluster: set true if you want you fork the main process depending of your CPU - server.https: enable/disable the https. It is needed to have the righ certificates to allow clients to connect under https - server.headers: put here all the response headers that you want to use, for example to enable the cross-origin resource sharing. - api.route: defines the main route of the api (e.g. /api) - api.modules: add in to this array all the module (js files for example Express middleware) that you want to use as api modules. - 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). - serviceRegistry.watchDog: enable/disable the auto-update for the service registry. Speficy the update seconds into the timer property - serviceRegistry.databse: configure here your MongoDb connection params. This database represents your Service Registry #Microservice Configuraiton Here, a detailed description of the config.json file for a Microservice ```javascript { "server":{ "id":"MicroNodeService", "port":8080, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"login", "route":"login"} ] }, "serviceRegistry":{ "watchDog":{ "isEnabled":false, "timer":30000 }, "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } } ``` where: - server.id: it is a key to identify the microservice - server.port: it is the port where the microservice is listen to - server,isCluster: set true if you want you fork the main process depending of your CPU - server.https: enable/disable the https. It is needed to have the righ certificates to allow clients to connect under https - server.headers: put here all the response headers that you want to use, for example to enable the cross-origin resource sharing. - api.route: defines the main route of the api (e.g. /api) - api.modules: add in to this array all the module (js files for example Express middleware) that you want to use as api modules - serviceRegistry.watchDog: enable/disable the auto-update for the service registry. Speficy the update seconds into the timer property - serviceRegistry.databse: configure here your MongoDb connection params. This database represents your Service Registry ![ScreenShot](https://raw.github.com/alchimya/micro-node-api-gateway/master/micro-node-api-gateway.gif) ================================================ FILE: api-gateway-and-service-doscovery/ServicesSetup.sh ================================================ cd service-login sudo npm install cd .. cd service-orders sudo npm install cd .. cd service-signup sudo npm install cd .. cd service-log sudo npm install cd .. cd api-gateway sudo npm install ================================================ FILE: api-gateway-and-service-doscovery/ServicesStart.sh ================================================ cd service-login DEBUG=http node server & cd .. cd service-orders DEBUG=http node server & cd .. cd service-signup DEBUG=http node server & cd .. cd service-log DEBUG=http node server & cd .. cd api-gateway DEBUG=http node server ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/Dockerbuild.sh ================================================ docker build -t micro-node-service-api-gateway:latest . winpty docker run -it --rm -p 8080:8080 --name micro-node-service-api-gateway micro-node-service-api-gateway:latest ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/Dockerfile ================================================ FROM node:6.2.0-onbuild EXPOSE 8080 ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/api/account/login.js ================================================ /** * Created by domenicovacchiano on 10/07/16. */ var express = require('express'), router = express.Router(), apiGateway = require('../.././api-gateway'); router.post('/', function (req, res,next) { var request = new apiGateway(); request.sendRequest("ServiceLogin","login",req, res,next); }); module.exports = router; ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/api/account/signup.js ================================================ /** * Created by domenicovacchiano on 10/07/16. */ var express = require('express'), router = express.Router(), apiGateway = require('../.././api-gateway'); router.post('/', function (req, res,next) { var request = new apiGateway(); request.sendRequest("ServiceSignup","signup",req, res,next); }); module.exports = router; ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/api/crm/orders/orders.js ================================================ /** * Created by domenicovacchiano on 10/07/16. */ var express = require('express'), router = express.Router(), apiGateway = require('../../.././api-gateway'); router.post('/', function (req, res,next) { var request = new apiGateway(); request.sendRequest("ServiceOrders","orders",req, res,next); }); module.exports = router; ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/api-gateway.js ================================================ /** * Created by domenicovacchiano on 10/07/16. */ var debug = require('debug')('http'), config= require ('./config')(), request = require('request'), servicesHelper = require('./services-helper')(config.services), serviceRegistry = require ('micro-node-service-registry-lib')({ name:config.serviceRegistry.database.name, user:config.serviceRegistry.database.user, password:config.serviceRegistry.database.password, host:config.serviceRegistry.database.host, port:config.serviceRegistry.database.port, connectionPool:config.serviceRegistry.database.connectionPool }); var ApiGateway = function () { }; ApiGateway.prototype.sendRequest=function (serviceName,serviceEndpointId,req, res,next) { service=servicesHelper.getService(serviceName,serviceEndpointId); serviceRegistry.find(service.name,service.endpointId,function (error,service) { if (service && !error){ console.log(service); request({ url: service.endpointUrl, method: 'POST', json:req.body }, function(error, response, body){ if (error){ return next(error) }else { debug(body); return res.status(response.statusCode).send(body); } }); } else { if (error){ return next(error); }else { return res.status(500).send(responseLib.errorResponse(1001,"Service not found","Application Error")); } } }); }; module.exports=ApiGateway; ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/config.js ================================================ /** * Created by domenicovacchiano on 25/05/16. */ var fs = require('fs'); function Config() { var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'), 'utf8'); return{ server:{ id:config.server.id, port:config.server.port, isCluster:config.server.isCluster, https:config.server.https, headers:config.server.headers, httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname + "/" + config.server.https.key) :null, httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname + "/" + config.server.https.ca) :null, }, api:{ route:config.api.route, modules:config.api.modules }, services:config.services, serviceRegistry:config.serviceRegistry }; } module.exports=Config; ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/config.json ================================================ { "server":{ "id":"MicroNodeApiGateway", "port":8080, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"login", "path":"api/account", "route":"account/login"}, {"name":"signup", "path":"api/account", "route":"account/signup"}, {"name":"orders", "path":"api/crm/orders", "route":"crm/orders"} ] }, "services":[ {"name":"ServiceLog", "endpointId":"log"}, {"name":"ServiceLogin", "endpointId":"login"}, {"name":"ServiceSignup", "endpointId":"signup"}, {"name":"ServiceOrders", "endpointId":"orders"} ], "serviceRegistry":{ "database":{ "name":"test", "user":"", "password":"", "host":"192.168.29.43", "port":27017 } } } ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/package.json ================================================ { "name": "DoorApiGateway", "version": "0.0.1", "description": "Api Gateway", "author": { "name": "Domenico Vacchiano", "email": "domenico@doorgames.com", "url": "http://www.doorgames.com" }, "homepage": "http://www.doorgames.com/", "repository": { "type": "git", "url": "" }, "engines": { "node": ">= 0.6.0", "npm": ">= 1.0.0" }, "dependencies": { "express": "^4.13.4", "body-parser": "^1.15.1", "jsonwebtoken": "^7.0.0", "request": "^2.72.0", "morgan": "^1.7.0", "micro-node-net-lib": "git@github.com:alchimya/micro-node-net-lib.git", "micro-node-service-registry-lib": "git@github.com:alchimya/micro-node-service-registry-lib.git" }, "private": true, "scripts": { "start": "node server.js" }, "main": "server.js" } ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/server.js ================================================ /** * Created by domenicovacchiano on 10/07/16. */ var config= require ('./config')(), express=require('express'), debug = require('debug')('http'), bodyParser = require('body-parser'), morgan= require('morgan'), cluster = require('cluster'), numCPUs = require('os').cpus().length, netLib = require ('micro-node-net-lib'), apiGateway = require('./api-gateway'), configServer= { server:{ port:config.server.port }, https:{ isEnabled:config.server.https.isEnabled, key:config.server.httpsKeyContent, ca:config.server.httpsCaContent }, express:{ app:null }, exitHandlers:["exit","SIGINT","SIGTERM"] }, server = netLib.server(configServer); if (cluster.isMaster && config.server.isCluster) { debug("cpus:" + numCPUs); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log("cluster exit"); debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code); cluster.fork(); }); } else { var app=express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(morgan('dev')); configServer.express.app = app; //header(s) setting app.all('/*', function(req, res, next) { config.server.headers.forEach(function(item) { //console.log(item); res.header(item.name, item.value); }); next(); }); //pu here a middleware to check the api key //load API route(s) config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.path + "/" + item.name)); }); server.create(function (err,server) { if (!err){ console.log("### " + config.server.id + " -> " + (config.server.https ? "HTTPS" : "HTTP") + " Server started on port " + config.server.port + (config.server.isCluster ? " cluster worker " + cluster.worker.id : "")); } else { debug(err); } }); //Http Error Handling on app.use(function(err, req, res, next) { debug(err); var request = new apiGateway(); request.sendRequest("ServiceLog","log",req, res,next); res.status(500).send({ code:1000, message:"Application Error", domain:"Application Error" }); }); } ================================================ FILE: api-gateway-and-service-doscovery/api-gateway/services-helper.js ================================================ /** * Created by domenicovacchiano on 11/07/16. */ function ServiceHelper(services) { return{ getServiceWithName:function (serviceName) { var service=services.filter(function( item ) { return item.name == serviceName; }); if (!service || !service[0] || service[0].length==0){ return null; } return service[0]; }, getService:function (serviceName,serviceEndpointId) { var service=services.filter(function( item ) { return (item.name == serviceName && item.endpointId == serviceEndpointId); }); if (!service || !service[0] || service[0].length==0){ return null; } return service[0]; } }; }; module.exports=ServiceHelper; ================================================ FILE: api-gateway-and-service-doscovery/service-log/Dockerbuild.sh ================================================ docker build -t micro-node-service-log:latest . winpty docker run -it --rm -p 8084:8084 --name micro-node-service-log micro-node-service-log:latest ================================================ FILE: api-gateway-and-service-doscovery/service-log/Dockerfile ================================================ FROM node:6.2.0-onbuild EXPOSE 8084 ================================================ FILE: api-gateway-and-service-doscovery/service-log/config.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var fs = require('fs'); function Config() { var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'), 'utf8'); return{ server:{ id:config.server.id, port:config.server.port, isCluster:config.server.isCluster, https:config.server.https, headers:config.server.headers, httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname + "/" + config.server.https.key) :null, httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname + "/" + config.server.https.ca) :null, }, api:{ route:config.api.route, modules:config.api.modules }, serviceRegistry:config.serviceRegistry }; } module.exports=Config; ================================================ FILE: api-gateway-and-service-doscovery/service-log/config.json ================================================ { "server":{ "id":"ServiceLog", "port":8084, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"log", "route":"log"} ] }, "serviceRegistry":{ "watchDog":{ "isEnabled":false, "timer":30000 }, "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } } ================================================ FILE: api-gateway-and-service-doscovery/service-log/log.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var express = require('express'), router = express.Router(), debug = require('debug')('http'), config= require ('./config')() router.post('/', function (req, res,next) { return res.status(200).send("## Log -> This is just a test response ;-)"); }); module.exports = router; ================================================ FILE: api-gateway-and-service-doscovery/service-log/package.json ================================================ { "name": "MicroNodeService", "version": "0.0.1", "description": "Micro Node Tutorial", "author": { "name": "Domenico Vacchiano", "email": "info@domenicovacchiano.com", "url": "http://www.domenicovacchiano.com" }, "homepage": "http://www.domenicovacchiano.com/", "repository": { "type": "git", "url": "" }, "engines": { "node": ">= 0.6.0", "npm": ">= 1.0.0" }, "dependencies": { "express": "^4.13.4", "body-parser": "^1.15.1", "request": "^2.72.0", "morgan": "^1.7.0", "network-address": "^1.1.0", "micro-node-net-lib": "git@github.com:alchimya/micro-node-net-lib.git", "micro-node-service-registry-lib": "git@github.com:alchimya/micro-node-service-registry-lib.git" }, "private": true, "scripts": { "start": "node server.js" }, "main": "server.js" } ================================================ FILE: api-gateway-and-service-doscovery/service-log/server.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var config= require ('./config')(), address = require('network-address'), express=require('express'), debug = require('debug')('http'), bodyParser = require('body-parser'), morgan= require('morgan'), cluster = require('cluster'), numCPUs = require('os').cpus().length, netLib = require ('micro-node-net-lib'), configServer= { server:{ port:config.server.port }, https:{ isEnabled:config.server.https.isEnabled, key:config.server.httpsKeyContent, ca:config.server.httpsCaContent }, express:{ app:null }, exitHandlers:["exit","SIGINT","SIGTERM"] } server = netLib.server(configServer), serviceRegistry = require ('micro-node-service-registry-lib')({ name:config.serviceRegistry.database.name, user:config.serviceRegistry.database.user, password:config.serviceRegistry.database.password, host:config.serviceRegistry.database.host, port:config.serviceRegistry.database.port, connectionPool:config.serviceRegistry.database.connectionPool }); if (cluster.isMaster && config.server.isCluster) { debug("cpus:" + numCPUs); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log("cluster exit"); debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code); cluster.fork(); }); } else { var app=express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(morgan('dev')); configServer.express.app = app; //header(s) setting app.all('/*', function(req, res, next) { config.server.headers.forEach(function(item) { //console.log(item); res.header(item.name, item.value); }); next(); }); //load API route(s) config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); }); server.create(function (err,server) { if (!err){ //load API route(s) and register services registerServer(); if (config.serviceRegistry.watchDog.isEnabled){ setInterval(function(){ registerServer(); }, config.serviceRegistry.watchDog.timer); } console.log("### " + config.server.id + " -> " + (config.server.https ? "HTTPS" : "HTTP") + " Server started on port " + config.server.port + (config.server.isCluster ? " cluster worker " + cluster.worker.id : "")); } else { debug(err); } }); server.registerExitHandler(function () { unregisterServer(); debug("Server Exit Handled"); }); var registerServer=function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("registerServer"); config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); serviceRegistry.register({ serviceId:config.server.id, serviceHost:address(), servicePort:config.server.port, serviceProtocol:config.server.https.isEnabled ? "https" : "http", endpointId:item.name, endpointPath:config.api.route + "/" + item.route }, function (err,item) { if (err){ console.log(app.next()) debug(err); } }); }); } }; var unregisterServer = function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("unregisterServer"); config.api.modules.forEach(function(item) { serviceRegistry.unregister(config.server.id,item.name,function (err,item) { if (err){ //TODO update flag inactive? console.log(err); } if (!config.server.isCluster){ process.exit(); } }); }); } }; } ================================================ FILE: api-gateway-and-service-doscovery/service-login/Dockerbuild.sh ================================================ docker build -t micro-node-service-login:latest . winpty docker run -it --rm -p 8081:8081 --name micro-node-service-login micro-node-service-login:latest ================================================ FILE: api-gateway-and-service-doscovery/service-login/Dockerfile ================================================ FROM node:6.2.0-onbuild EXPOSE 8081 ================================================ FILE: api-gateway-and-service-doscovery/service-login/config.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var fs = require('fs'); function Config() { var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'), 'utf8'); return{ server:{ id:config.server.id, port:config.server.port, isCluster:config.server.isCluster, https:config.server.https, headers:config.server.headers, httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname + "/" + config.server.https.key) :null, httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname + "/" + config.server.https.ca) :null, }, api:{ route:config.api.route, modules:config.api.modules }, serviceRegistry:config.serviceRegistry }; } module.exports=Config; ================================================ FILE: api-gateway-and-service-doscovery/service-login/config.json ================================================ { "server":{ "id":"ServiceLogin", "port":8081, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"login", "route":"login"} ] }, "serviceRegistry":{ "watchDog":{ "isEnabled":false, "timer":30000 }, "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } } ================================================ FILE: api-gateway-and-service-doscovery/service-login/login.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var express = require('express'), router = express.Router(), debug = require('debug')('http'), config= require ('./config')() router.post('/', function (req, res,next) { return res.status(200).send("## Login -> This is just a test response ;-)"); }); module.exports = router; ================================================ FILE: api-gateway-and-service-doscovery/service-login/package.json ================================================ { "name": "MicroNodeService", "version": "0.0.1", "description": "Micro Node Tutorial", "author": { "name": "Domenico Vacchiano", "email": "info@domenicovacchiano.com", "url": "http://www.domenicovacchiano.com" }, "homepage": "http://www.domenicovacchiano.com/", "repository": { "type": "git", "url": "" }, "engines": { "node": ">= 0.6.0", "npm": ">= 1.0.0" }, "dependencies": { "express": "^4.13.4", "body-parser": "^1.15.1", "request": "^2.72.0", "morgan": "^1.7.0", "network-address": "^1.1.0", "micro-node-net-lib": "git@github.com:alchimya/micro-node-net-lib.git", "micro-node-service-registry-lib": "git@github.com:alchimya/micro-node-service-registry-lib.git" }, "private": true, "scripts": { "start": "node server.js" }, "main": "server.js" } ================================================ FILE: api-gateway-and-service-doscovery/service-login/server.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var config= require ('./config')(), address = require('network-address'), express=require('express'), debug = require('debug')('http'), bodyParser = require('body-parser'), morgan= require('morgan'), cluster = require('cluster'), numCPUs = require('os').cpus().length, netLib = require ('micro-node-net-lib'), configServer= { server:{ port:config.server.port }, https:{ isEnabled:config.server.https.isEnabled, key:config.server.httpsKeyContent, ca:config.server.httpsCaContent }, express:{ app:null }, exitHandlers:["exit","SIGINT","SIGTERM"] } server = netLib.server(configServer), serviceRegistry = require ('micro-node-service-registry-lib')({ name:config.serviceRegistry.database.name, user:config.serviceRegistry.database.user, password:config.serviceRegistry.database.password, host:config.serviceRegistry.database.host, port:config.serviceRegistry.database.port, connectionPool:config.serviceRegistry.database.connectionPool }); if (cluster.isMaster && config.server.isCluster) { debug("cpus:" + numCPUs); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log("cluster exit"); debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code); cluster.fork(); }); } else { var app=express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(morgan('dev')); configServer.express.app = app; //header(s) setting app.all('/*', function(req, res, next) { config.server.headers.forEach(function(item) { //console.log(item); res.header(item.name, item.value); }); next(); }); //load API route(s) config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); }); server.create(function (err,server) { if (!err){ //load API route(s) and register services registerServer(); if (config.serviceRegistry.watchDog.isEnabled){ setInterval(function(){ registerServer(); }, config.serviceRegistry.watchDog.timer); } console.log("### " + config.server.id + " -> " + (config.server.https ? "HTTPS" : "HTTP") + " Server started on port " + config.server.port + (config.server.isCluster ? " cluster worker " + cluster.worker.id : "")); } else { debug(err); } }); server.registerExitHandler(function () { unregisterServer(); debug("Server Exit Handled"); }); var registerServer=function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("registerServer"); config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); serviceRegistry.register({ serviceId:config.server.id, serviceHost:address(), servicePort:config.server.port, serviceProtocol:config.server.https.isEnabled ? "https" : "http", endpointId:item.name, endpointPath:config.api.route + "/" + item.route }, function (err,item) { if (err){ console.log(app.next()) debug(err); } }); }); } }; var unregisterServer = function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("unregisterServer"); config.api.modules.forEach(function(item) { serviceRegistry.unregister(config.server.id,item.name,function (err,item) { if (err){ //TODO update flag inactive? console.log(err); } if (!config.server.isCluster){ process.exit(); } }); }); } }; } ================================================ FILE: api-gateway-and-service-doscovery/service-orders/Dockerbuild.sh ================================================ docker build -t micro-node-service-orders:latest . winpty docker run -it --rm -p 8083:8083 --name micro-node-service-orders micro-node-service-orders:latest ================================================ FILE: api-gateway-and-service-doscovery/service-orders/Dockerfile ================================================ FROM node:6.2.0-onbuild EXPOSE 8083 ================================================ FILE: api-gateway-and-service-doscovery/service-orders/config.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var fs = require('fs'); function Config() { var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'), 'utf8'); return{ server:{ id:config.server.id, port:config.server.port, isCluster:config.server.isCluster, https:config.server.https, headers:config.server.headers, httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname + "/" + config.server.https.key) :null, httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname + "/" + config.server.https.ca) :null, }, api:{ route:config.api.route, modules:config.api.modules }, serviceRegistry:config.serviceRegistry }; } module.exports=Config; ================================================ FILE: api-gateway-and-service-doscovery/service-orders/config.json ================================================ { "server":{ "id":"ServiceOrders", "port":8083, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"orders", "route":"orders"} ] }, "serviceRegistry":{ "watchDog":{ "isEnabled":false, "timer":30000 }, "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } } ================================================ FILE: api-gateway-and-service-doscovery/service-orders/orders.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var express = require('express'), router = express.Router(), debug = require('debug')('http'), config= require ('./config')() router.post('/', function (req, res,next) { return res.status(200).send("## Orders -> This is just a test response ;-)"); }); module.exports = router; ================================================ FILE: api-gateway-and-service-doscovery/service-orders/package.json ================================================ { "name": "MicroNodeService", "version": "0.0.1", "description": "Micro Node Tutorial", "author": { "name": "Domenico Vacchiano", "email": "info@domenicovacchiano.com", "url": "http://www.domenicovacchiano.com" }, "homepage": "http://www.domenicovacchiano.com/", "repository": { "type": "git", "url": "" }, "engines": { "node": ">= 0.6.0", "npm": ">= 1.0.0" }, "dependencies": { "express": "^4.13.4", "body-parser": "^1.15.1", "request": "^2.72.0", "morgan": "^1.7.0", "network-address": "^1.1.0", "micro-node-net-lib": "git@github.com:alchimya/micro-node-net-lib.git", "micro-node-service-registry-lib": "git@github.com:alchimya/micro-node-service-registry-lib.git" }, "private": true, "scripts": { "start": "node server.js" }, "main": "server.js" } ================================================ FILE: api-gateway-and-service-doscovery/service-orders/server.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var config= require ('./config')(), address = require('network-address'), express=require('express'), debug = require('debug')('http'), bodyParser = require('body-parser'), morgan= require('morgan'), cluster = require('cluster'), numCPUs = require('os').cpus().length, netLib = require ('micro-node-net-lib'), configServer= { server:{ port:config.server.port }, https:{ isEnabled:config.server.https.isEnabled, key:config.server.httpsKeyContent, ca:config.server.httpsCaContent }, express:{ app:null }, exitHandlers:["exit","SIGINT","SIGTERM"] } server = netLib.server(configServer), serviceRegistry = require ('micro-node-service-registry-lib')({ name:config.serviceRegistry.database.name, user:config.serviceRegistry.database.user, password:config.serviceRegistry.database.password, host:config.serviceRegistry.database.host, port:config.serviceRegistry.database.port, connectionPool:config.serviceRegistry.database.connectionPool }); if (cluster.isMaster && config.server.isCluster) { debug("cpus:" + numCPUs); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log("cluster exit"); debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code); cluster.fork(); }); } else { var app=express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(morgan('dev')); configServer.express.app = app; //header(s) setting app.all('/*', function(req, res, next) { config.server.headers.forEach(function(item) { //console.log(item); res.header(item.name, item.value); }); next(); }); //load API route(s) config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); }); server.create(function (err,server) { if (!err){ //load API route(s) and register services registerServer(); if (config.serviceRegistry.watchDog.isEnabled){ setInterval(function(){ registerServer(); }, config.serviceRegistry.watchDog.timer); } console.log("### " + config.server.id + " -> " + (config.server.https ? "HTTPS" : "HTTP") + " Server started on port " + config.server.port + (config.server.isCluster ? " cluster worker " + cluster.worker.id : "")); } else { debug(err); } }); server.registerExitHandler(function () { unregisterServer(); debug("Server Exit Handled"); }); var registerServer=function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("registerServer"); config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); serviceRegistry.register({ serviceId:config.server.id, serviceHost:address(), servicePort:config.server.port, serviceProtocol:config.server.https.isEnabled ? "https" : "http", endpointId:item.name, endpointPath:config.api.route + "/" + item.route }, function (err,item) { if (err){ console.log(app.next()) debug(err); } }); }); } }; var unregisterServer = function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("unregisterServer"); config.api.modules.forEach(function(item) { serviceRegistry.unregister(config.server.id,item.name,function (err,item) { if (err){ //TODO update flag inactive? console.log(err); } if (!config.server.isCluster){ process.exit(); } }); }); } }; } ================================================ FILE: api-gateway-and-service-doscovery/service-signup/Dockerbuild.sh ================================================ docker build -t micro-node-service-signup:latest . winpty docker run -it --rm -p 8082:8082 --name micro-node-service-signup micro-node-service-signup:latest ================================================ FILE: api-gateway-and-service-doscovery/service-signup/Dockerfile ================================================ FROM node:6.2.0-onbuild EXPOSE 8082 ================================================ FILE: api-gateway-and-service-doscovery/service-signup/config.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var fs = require('fs'); function Config() { var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'), 'utf8'); return{ server:{ id:config.server.id, port:config.server.port, isCluster:config.server.isCluster, https:config.server.https, headers:config.server.headers, httpsKeyContent:config.server.https.key ? fs.readFileSync(__dirname + "/" + config.server.https.key) :null, httpsCaContent:config.server.https.ca ? fs.readFileSync(__dirname + "/" + config.server.https.ca) :null, }, api:{ route:config.api.route, modules:config.api.modules }, serviceRegistry:config.serviceRegistry }; } module.exports=Config; ================================================ FILE: api-gateway-and-service-doscovery/service-signup/config.json ================================================ { "server":{ "id":"ServiceSignup", "port":8082, "isCluster":true, "https":{ "isEnabled":false, "key":"", "ca":"" }, "headers":[ {"name":"Access-Control-Allow-Origin","value":"*"}, {"name":"Access-Control-Allow-Headers","value":"Origin, X-Requested-With, Content-Type, Accept"}, {"name":"Access-Control-Allow-Methods","value":"GET,PUT,POST,DELETE,OPTIONS"} ] }, "api":{ "route":"api", "modules":[ {"name":"signup", "route":"signup"} ] }, "serviceRegistry":{ "watchDog":{ "isEnabled":false, "timer":30000 }, "database":{ "name":"my_mongo_db", "user":"my_mongo_db_user", "password":"my_mongo_db_password", "host":"my_mongo_db_host", "port":27017 } } } ================================================ FILE: api-gateway-and-service-doscovery/service-signup/package.json ================================================ { "name": "MicroNodeService", "version": "0.0.1", "description": "Micro Node Tutorial", "author": { "name": "Domenico Vacchiano", "email": "info@domenicovacchiano.com", "url": "http://www.domenicovacchiano.com" }, "homepage": "http://www.domenicovacchiano.com/", "repository": { "type": "git", "url": "" }, "engines": { "node": ">= 0.6.0", "npm": ">= 1.0.0" }, "dependencies": { "express": "^4.13.4", "body-parser": "^1.15.1", "request": "^2.72.0", "morgan": "^1.7.0", "network-address": "^1.1.0", "micro-node-net-lib": "git@github.com:alchimya/micro-node-net-lib.git", "micro-node-service-registry-lib": "git@github.com:alchimya/micro-node-service-registry-lib.git" }, "private": true, "scripts": { "start": "node server.js" }, "main": "server.js" } ================================================ FILE: api-gateway-and-service-doscovery/service-signup/server.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var config= require ('./config')(), address = require('network-address'), express=require('express'), debug = require('debug')('http'), bodyParser = require('body-parser'), morgan= require('morgan'), cluster = require('cluster'), numCPUs = require('os').cpus().length, netLib = require ('micro-node-net-lib'), configServer= { server:{ port:config.server.port }, https:{ isEnabled:config.server.https.isEnabled, key:config.server.httpsKeyContent, ca:config.server.httpsCaContent }, express:{ app:null }, exitHandlers:["exit","SIGINT","SIGTERM"] } server = netLib.server(configServer), serviceRegistry = require ('micro-node-service-registry-lib')({ name:config.serviceRegistry.database.name, user:config.serviceRegistry.database.user, password:config.serviceRegistry.database.password, host:config.serviceRegistry.database.host, port:config.serviceRegistry.database.port, connectionPool:config.serviceRegistry.database.connectionPool }); if (cluster.isMaster && config.server.isCluster) { debug("cpus:" + numCPUs); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log("cluster exit"); debug('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code); cluster.fork(); }); } else { var app=express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(morgan('dev')); configServer.express.app = app; //header(s) setting app.all('/*', function(req, res, next) { config.server.headers.forEach(function(item) { //console.log(item); res.header(item.name, item.value); }); next(); }); //load API route(s) config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); }); server.create(function (err,server) { if (!err){ //load API route(s) and register services registerServer(); if (config.serviceRegistry.watchDog.isEnabled){ setInterval(function(){ registerServer(); }, config.serviceRegistry.watchDog.timer); } console.log("### " + config.server.id + " -> " + (config.server.https ? "HTTPS" : "HTTP") + " Server started on port " + config.server.port + (config.server.isCluster ? " cluster worker " + cluster.worker.id : "")); } else { debug(err); } }); server.registerExitHandler(function () { unregisterServer(); debug("Server Exit Handled"); }); var registerServer=function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("registerServer"); config.api.modules.forEach(function(item) { //console.log(item); app.use('/' + config.api.route + "/" + item.route, require('./' + item.name)); serviceRegistry.register({ serviceId:config.server.id, serviceHost:address(), servicePort:config.server.port, serviceProtocol:config.server.https.isEnabled ? "https" : "http", endpointId:item.name, endpointPath:config.api.route + "/" + item.route }, function (err,item) { if (err){ console.log(app.next()) debug(err); } }); }); } }; var unregisterServer = function () { if (!config.server.isCluster || cluster.worker.id===1){ debug("unregisterServer"); config.api.modules.forEach(function(item) { serviceRegistry.unregister(config.server.id,item.name,function (err,item) { if (err){ //TODO update flag inactive? console.log(err); } if (!config.server.isCluster){ process.exit(); } }); }); } }; } ================================================ FILE: api-gateway-and-service-doscovery/service-signup/signup.js ================================================ /** * Created by domenicovacchiano on 07/07/16. */ var express = require('express'), router = express.Router(), debug = require('debug')('http'), config= require ('./config')() router.post('/', function (req, res,next) { return res.status(200).send("## Signup -> This is just a test response ;-)"); }); module.exports = router; ================================================ FILE: dockerized-containers/.eslintrc.js ================================================ module.exports = { "extends": "airbnb-base", "rules": { "comma-dangle": 0, "no-console": 0, "no-unused-vars" :0 } }; ================================================ FILE: dockerized-containers/.gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) ### Node template # Logs logs *.log npm-debug.log* /dist .vscode /test /*/dist # Runtime data pids *.pid /node_modules *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages package-lock.json # Optional npm cache directory .npm # Optional REPL history .node_repl_history # Jetbrains dir .idea/ .DS_Store # github dir .github/ # .env files bin/dev.env bin/test.env ================================================ FILE: dockerized-containers/.travis.yml ================================================ language: node_js sudo: false node_js: - 10 install: - npm install script: - npm test ================================================ FILE: dockerized-containers/README.md ================================================ # Application for e-commerce Hub REST API to support application features - Express as web framework with Typescript - Passport js for social authentication - Express CORS enabled - boom for error codes & Joi for Validation - Winston for logging and express minitor for monitoring - Mongoose as ODM driver - eslint validation extending airbnb styleguide - git hooks & CI/CD in place - Typescript based compilation tsc compiler - TDD in progress with Mocha - JWT based authentication - multiple Mongoose collection with referencing - payment gateway Integration - Heroku deployment - Mini e-commerce platform # Cart Application # "It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills - microservices architecture - Client application in React - User Auth microservices - Cart services - Admin Microservices ![deividing services](/screens/02.png "title") ![Micro services with Node JS](/screens/03.png "title") ``` # Application Execution ```javascript git clone repo npm install npm run startdev tsc -- watch ``` # Application configuration ```javascript env.sh need to be added locally export NODE_ENV="dev" export PORT="3005" export MONGOURL="mongodb://mongo/hello" export EXPRESS_SESSION_SECRET="************************" export F_CLIENTID="**************" export F_CLIENTSECRET="**********************" ``` # update etc/hosts file ``` ## # Host Database # # localhost is used to configure the loopback interface # when the system is booting. Do not change this entry. ## 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost 127.0.0.1 mysql redis mongo 127.0.0.1 ms-commerce.com ``` # Sevices end-point - http://ms-commerce.com/api/v1 Auth services - http://ms-commerce.com/admin/v1 Admin APIs - http://ms-commerce.com/admin/v1 Cart APIs # Application NPM Script ```javascript "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "clean" : "rm -rf dist", "copy" : "cp -r uploads dist/ && cp -r app/global dist/app/" ``` ================================================ FILE: dockerized-containers/docker-compose.yml ================================================ version: '3.5' services: gateway: image: nginx:1.11 ports: - 80:80 - 443:443 volumes: - ./proxy/default.conf:/etc/nginx/conf.d/default.conf:ro - ./proxy/ssl:/etc/nginx/ssl:ro depends_on: - ms_commerce_auth - ms_commerce_admin - ms_commerce_client networks: - ms_network ms_mysql: container_name: ms_mysql image: mysql:5.7 volumes: - ~/datadir/mysql:/var/lib/mysql ports: - 3306:3306 - 33060:33060 environment: MYSQL_ROOT_PASSWORD: root networks: - ms_network ms_commerce_mongo: image: mongo container_name: ms_commerce_mongo restart: unless-stopped volumes: - ~/datadir/mongo:/data/db ports: - 27017:27017 networks: - ms_network ms_commerce_auth: container_name: ms_commerce_auth build: ./e-Commerce-Auth/ image: e-commerce-auth volumes: - ./e-Commerce-Auth/:/usr/src/app - /usr/src/app/node_modules ports: - 3001:3001 - 9201:9201 depends_on: - ms_mysql networks: - ms_network ms_commerce_cart: container_name: ms_commerce_cart build: ./e-Commerce-Cart/ image: e-commerce-cart volumes: - ./e-Commerce-Cart/:/usr/src/app - /usr/src/app/node_modules ports: - 3004:3004 - 9204:9204 depends_on: - ms_mysql networks: - ms_network ms_commerce_admin: build: ./e-Commerce-Admin/ image: e-commerce-admin container_name: ms_commerce_admin environment: - NODE_ENV=local volumes: - ./e-Commerce-Admin/:/usr/src/app - /usr/src/app/node_modules ports: - 3002:3002 - 9202:9202 depends_on: - ms_commerce_mongo networks: - ms_network ms_commerce_client: build: ./e-Commerce-Client/ image: e-commerce-client container_name: ms_commerce_client environment: - NODE_ENV=local volumes: - ./e-Commerce-Client/:/usr/src/app - /usr/src/app/node_modules ports: - 3003:3003 depends_on: - ms_commerce_admin - ms_commerce_auth networks: - ms_network networks: ms_network: driver: bridge name: ms_network ================================================ FILE: dockerized-containers/e-Commerce-Admin/Dockerfile ================================================ FROM node:carbon # Create app directory WORKDIR /usr/src/app # Bundle app source COPY . . # npm install RUN npm install # Run npm install --global grpc --unsafe-perm EXPOSE 3002 9202 CMD [ "npm", "run", "watchserver" ] CMD [ "npm", "run", "startdev" ] ================================================ FILE: dockerized-containers/e-Commerce-Admin/README.md ================================================ # Application for e-commerce Hub REST API to support application features - Express as web framework with Typescript - Passport js for social authentication - Express CORS enabled - boom for error codes & Joi for Validation - Winston for logging and express minitor for monitoring - Mongoose as ODM driver - eslint validation extending airbnb styleguide - git hooks & CI/CD in place - Typescript based compilation tsc compiler - TDD in progress with Mocha - JWT based authentication - multiple Mongoose collection with referencing - payment gateway Integration - Heroku deployment - Mini e-commerce platform # Cart Application # "It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills ``` # Application Execution ```javascript git clone repo npm install npm run startdev tsc -- watch ``` # Application configuration ```javascript env.sh need to be added locally export NODE_ENV="dev" export PORT="3005" export MONGOURL="mongodb://mongo/hello" export EXPRESS_SESSION_SECRET="************************" export F_CLIENTID="**************" export F_CLIENTSECRET="**********************" ``` # Application NPM Script ```javascript "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "clean" : "rm -rf dist", "copy" : "cp -r uploads dist/ && cp -r app/global dist/app/" ``` ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/config/email.ts ================================================ 'use strict'; export default { global: { from: 'info@kpilibrary.com', }, welcome: { subject: 'Welcome to KPI Library', }, password_reset: { subject: 'KPI Library: Reset your password', }, event_booked_guest: { subject: 'KPI Library: Your Booking Has Been Confirmed', }, event_booked_host: { subject: 'KPI Library: Your Event Has Been Booked', }, event_booked_guests_notification: { subject: 'KPI Library: Your Booking Has Been Confirmed', }, message_received: { subject: 'KPI Library: New Message Received', }, guest_review_email: { subject: 'KPI Library: Event Completed', }, alacarte_booked_guest: { subject: 'KPI Library: Alacarte Booking Details', }, alacarte_booked_host: { subject: 'KPI Library: Your Alacarte Has Been Booked', } } ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/config/environments/dev.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/config/environments/qa.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/config/environments/test.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/controller/UserController.ts ================================================ export { }; const uuidv4 = require('uuid/v4'); import User from '../models/user'; declare function require(name: string); import Helper from '../helper/bcrypt'; const jwt = require('jsonwebtoken'); import helper from '../helper/bcrypt'; import mailEvents from '../events/notification'; import logger from '../helper/logger'; import email from '../helper/email'; const saltRounds = 10; class userController { static getUserByEmail(email, cb) { User.findOne({ 'email': email }, (error, user) => { if (user) { cb(null, user); } else { cb('User does not exist in system', null); } }); } static validateUser(req, res, cb) { const { body } = req; User.find({ email: body.email }) .then((data) => { if (data && data.length) { const flag = helper.comparePassword(body.password, data[0].password) if (flag) { jwt.sign(helper.buildUserToken(data[0]), 'secretkey', (tokError, token) => { cb(null, token); }); } else { cb(new Error('username password does not match'), null); } } else { cb(new Error('no user found with this account email'), null); } }); } static registerDefault(req, res, cb) { const { body } = req; const { location } = req; const hash = helper.generateSaltValue(body.password); return User.find({ email: body.email }).then((user) => { if (user && user.length > 0) { cb(new Error('user already regitsered with us'), null); } else { return User.create(this.buildUser(body, hash, location) , (error, user) => { if (error) { cb(error, null); } else { logger.info('emitting user create event'); mailEvents.emit("welcome", user); cb(null, user); } }); } }); } static buildUser(body, hash = null, location = null) { const build = { username: body.username, phone: body.phone, email: body.email, email_verified: false, phone_verified: false, picture: body.picture ? body.picture : null, status: 1, gender: null, documents: [], type: 1, social: body.meta, uuid: uuidv4() } return hash ? Object.assign({}, build, { password: hash }) : build; } static registerSocial(user, callback) { User.findOne({ email: user.email }, (error, existingUser) => { if (existingUser) { callback(null, (existingUser)); } else { User.create(this.buildUser(user, null), (err, user) => { if (err) { callback(err, null); } else { callback(null, user); mailEvents.emit("welcome", user); } }); } }); } static activateUserAccount(uuid, cb) { User.findOne({ 'uuid': uuid }, (error, foundUser) => { if (foundUser) { foundUser.email_verified = true; foundUser.save(function (err) { if (err) { cb('error occoured while updating record'); } else { cb(null, 'done'); } }); } else { cb('User does not exist in system'); } }); } static resetPassword(email, callback) { // just generate password and send new password on mail User.findOne({ 'email': email }, (error, foundUser) => { if (foundUser) { let password = Math.random().toString(36).slice(2); const hash = helper.generateSaltValue(password); foundUser.password = hash; foundUser.save(function (err) { if (err) { callback('error occoured while updating record'); } else { mailEvents.emit("forgotPassword", foundUser, password); callback(null, 'done'); } }); } else { callback('User does not exist in system with this email'); } }); } static changeUserRole(req, callback) { const email = req.params.email const body = req.body User.findOne({ 'email': email }, (error, user) => { if (user) { user.type = 2; user.save(function (err, updated_user) { if (err) { callback('error occoured while chaging role'); } else { callback(null, updated_user); } }); } else { callback('user not found in system', null); } }); } static updateUser(email, data, callback) { User.findOne({ 'email': email }, (error, user) => { if (user) { if (data.username) { user.username = data.username; } if (data.gender) { user.gender = data.gender; } if (data.phone) { user.phone = data.phone; } if (data.profile_picture) { user.profile_picture = data.profile_picture; } if (data.password && data.password === data.confirm_password) { const hash = helper.generateSaltValue(data.password); user.password = hash; } if ( data.picture ) { user.picture = Helper.avatarURL(data.picture) } if (data.phone_verified) { user.phone_verified = true; } if (data.document) { user.documents.push(data.document); } if (data.meta) { user.meta = { about: data.meta.about || '', fun_fact: data.meta.fun_fact || '', payment: data.meta.payment || '', } } user.save(function (err, updated_user) { if (err) { callback('error occoured while updating record'); } else { callback(null, updated_user); } }); } else { callback('user not found', null); } }); } } export default userController; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/events/notification.ts ================================================ import Email from '../helper/email'; declare function require(name: string); const events = require('events'); const winston = require('winston'); // import Twillo from '../helper/twillo'; const eventEmitter = new events.EventEmitter(); eventEmitter.on('welcome', (user) => { winston.log('info', `sending welcome email to ${user.email}`); // Twillo.default_notification(user.phone, 'welcome') Email.welcome(user); }); eventEmitter.on('forgotPassword', (user, password, uuid) => { winston.log('info', `sending forgotPassword email to ${user.email}`); Email.password_reset(user, password); // Twillo.default_notification(user.phone, 'welcome') }); export default eventEmitter; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/global/templates/emails/password-reset-email/html.pug ================================================ html(lang='en') head meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') title password has successfully been reset link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet') link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico') link(rel='stylesheet', href='../assets/styles/style.css', type='text/css') body(data-gr-c-s-loaded='true', style='') .template-wrapper table.body(border='0', cellpadding='0', cellspacing='0') tbody tr td   td.container .content table.main tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td a.template-logo(href='../index.html') img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='') p.lead | Hello #{user.email}, br | Your password has successfully been reset table(border='0', cellpadding='0', cellspacing='0') tbody tr td.mt30.mb30(align='center') table(border='0', cellpadding='0', cellspacing='0') tbody tr td p.user-text span Your new password is #[pre #{password}] br a.btn-primary(href= login_url) Login p Thank you p.mb0 | If you have any problems, please contact me at a.click-link(href='#') admin@gmail.com table.help-section tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td h2.text-center.mb0 Need more help? a.support-link(href='#') We're here,ready to here table tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td p | You received this email beacuse you just signed up for new account. If it look weird a.default-link(href='#') view it in your browser .footer table(border='0', cellpadding='0', cellspacing='0') tbody tr td.content-block p.text-center | © 2018 KPI App, Goa India br | If these emails get annoying, please feel to a(href='#') unsubscribe td   ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/global/templates/emails/password-reset-email/style.css ================================================ @charset "UTF-8"; /* ------------------------------------- GLOBAL RESETS ------------------------------------- */ .container { display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } img { border: none; -ms-interpolation-mode: bicubic; max-width: 100%; } body { background-color: #f6f6f6; font-family: 'Rubik', sans-serif; font-size: 15px; line-height: 28px; -webkit-font-smoothing: antialiased; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } table { border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; } table td { font-family: sans-serif; font-size: 14px; vertical-align: top; } /* ------------------------------------- BODY & CONTAINER ------------------------------------- */ .body { background-color: #f6f6f6; width: 100%; } .lead { font-size: 18px; } .mt30 { margin-top: 30px; display: block; } .mb30 { margin-bottom: 30px; display: block; } /* 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 */ .container { display: block; Margin: 0 auto !important; /* makes it centered */ max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } /* This should also be a block element, so that it will fill 100% of the .container */ .content { box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; } /* ------------------------------------- HEADER, FOOTER, MAIN ------------------------------------- */ .template-wrapper { background-color: #03A9F4; width: 100%; height: 250px; position: relative; } .click-link { color: #03A9F4; display: inline-block; margin-bottom: 20px; } .help-section { background-color: #ffdcdc; border-radius: 3px; width: 100%; text-align: center; } .mb0 { margin-bottom: 0px; } .support-link { color: #03A9F4; display: inline-block; font-size: 19px; margin-bottom: 0px; } .template-logo { display: block; margin-bottom: 40px; margin: auto; } .user-text { font-size: 18px; font-weight: 500; } .user-text span { font-weight: 600; } .text-secondary { color: #218ef4 !important } .main { background: #ffffff; border-radius: 3px; width: 100%; margin-bottom: 20px; } .wrapper { box-sizing: border-box; padding: 40px 25px; } .content-block { padding-bottom: 10px; padding-top: 10px; line-height: 2; } .footer { clear: both; text-align: center; width: 100%; } .footer td, .footer p, .footer span, .footer a { color: #999999; font-size: 12px; text-align: center; } /* ------------------------------------- TYPOGRAPHY ------------------------------------- */ h1, h2, h3, h4 { color: #000000; font-family: sans-serif; font-weight: 400; line-height: 1.4; margin: 0; Margin-bottom: 30px; } h1 { font-size: 35px; font-weight: 300; text-align: center; text-transform: capitalize; } p, ul, ol { font-family: sans-serif; font-size: 15px; font-weight: normal; margin: 0; margin-bottom: 15px; } p li, ul li, ol li { list-style-position: inside; margin-left: 5px; } a { color: #3498db; text-decoration: underline; } /* ------------------------------------- BUTTONS ------------------------------------- */ .btn { box-sizing: border-box; width: 100%; } .btn>tbody>tr>td { padding-bottom: 15px; } .btn table { width: auto; } .btn table td { background-color: #ffffff; border-radius: 5px; text-align: center; } .btn a { background-color: #ffffff; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; color: #3498db; cursor: pointer; display: inline-block; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-decoration: none; text-transform: capitalize; } .btn-primary table td { background-color: #3498db; } .btn-primary a { background-color: #03A9F4; border-color: #03A9F4; color: #ffffff; } .default-link { color: #03A9F4; } .default-link:hover { color: #03A9F4; } /* ------------------------------------- OTHER STYLES THAT MIGHT BE USEFUL ------------------------------------- */ .last { margin-bottom: 0; } .first { margin-top: 0; } .align-center { text-align: center; } .align-right { text-align: right; } .align-left { text-align: left; } .clear { clear: both; } .mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; } .preheader { color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; visibility: hidden; width: 0; } .powered-by a { text-decoration: none; } hr { border: 0; border-bottom: 1px solid #f6f6f6; Margin: 20px 0; } /* ------------------------------------- RESPONSIVE AND MOBILE FRIENDLY STYLES ------------------------------------- */ @media only screen and (max-width: 620px) { table[class=body] h1 { font-size: 28px !important; margin-bottom: 10px !important; } table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a { font-size: 16px !important; } table[class=body] .wrapper, table[class=body] .article { padding: 10px !important; } table[class=body] .content { padding: 0 !important; } table[class=body] .container { padding: 0 !important; width: 100% !important; } table[class=body] .main { border-left-width: 0 !important; border-radius: 0 !important; border-right-width: 0 !important; } table[class=body] .btn table { width: 100% !important; } table[class=body] .btn a { width: 100% !important; } table[class=body] .img-responsive { height: auto !important; max-width: 100% !important; width: auto !important; } } /* ------------------------------------- PRESERVE THESE STYLES IN THE HEAD ------------------------------------- */ @media all { .ExternalClass { width: 100%; } .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; } .apple-link a { color: inherit !important; font-family: inherit !important; font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; text-decoration: none !important; } .btn-primary table td:hover { background-color: #34495e !important; } .btn-primary a:hover { background-color: #03A9F4 !important; border-color: #03A9F4 !important; } } .btn-primary { text-decoration: none; color: #FFF; background-color: #03A9F4; border: solid #03A9F4; border-width: 6px 18px; line-height: 2em; /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ /*line-height: 28px;*/ font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 4px; text-transform: capitalize; } ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/global/templates/emails/welcome-email/html.pug ================================================ html(lang='en') head meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') title Account Activation email || KPI Library link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet') link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico') link(rel='stylesheet', href='../assets/styles/style.css', type='text/css') body(data-gr-c-s-loaded='true', style='') .template-wrapper table.body(border='0', cellpadding='0', cellspacing='0') tbody tr td   td.container .content table.main tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td a.template-logo(href='../index.html') img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='') p.lead | Hello KPI Library, br | Thanks for Signup on KPI App br | We have sent User Account Activation Link below table(border='0', cellpadding='0', cellspacing='0') tbody tr td.mt30.mb30(align='center') table(border='0', cellpadding='0', cellspacing='0') tbody tr td p.user-text | Hi, span #{user.email}, br br a.btn-primary(href= activate_url) Activate your Account p Thank you p.mb0 | If you have any problems, please contact me at a.click-link(href='#') admin@gmail.com table.help-section tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td h2.text-center.mb0 Need more help? a.support-link(href='#') We're here,ready to here table tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td p | You received this email beacuse you just signed up for new account. If it look weird a.default-link(href='#') view it in your browser .footer table(border='0', cellpadding='0', cellspacing='0') tbody tr td.content-block p.text-center | © 2018 KPI App, Goa India br | If these emails get annoying, please feel to a(href='#') unsubscribe td   ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/global/templates/emails/welcome-email/style.css ================================================ @charset "UTF-8"; /* ------------------------------------- GLOBAL RESETS ------------------------------------- */ .container { display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } img { border: none; -ms-interpolation-mode: bicubic; max-width: 100%; } body { background-color: #f6f6f6; font-family: 'Rubik', sans-serif; font-size: 15px; line-height: 28px; -webkit-font-smoothing: antialiased; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } table { border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; } table td { font-family: sans-serif; font-size: 14px; vertical-align: top; } /* ------------------------------------- BODY & CONTAINER ------------------------------------- */ .body { background-color: #f6f6f6; width: 100%; } .lead { font-size: 18px; } .mt30 { margin-top: 30px; display: block; } .mb30 { margin-bottom: 30px; display: block; } /* 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 */ .container { display: block; Margin: 0 auto !important; /* makes it centered */ max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } /* This should also be a block element, so that it will fill 100% of the .container */ .content { box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; } /* ------------------------------------- HEADER, FOOTER, MAIN ------------------------------------- */ .template-wrapper { background-color: #03A9F4; width: 100%; height: 250px; position: relative; } .click-link { color: #03A9F4; display: inline-block; margin-bottom: 20px; } .help-section { background-color: #ffdcdc; border-radius: 3px; width: 100%; text-align: center; } .mb0 { margin-bottom: 0px; } .support-link { color: #03A9F4; display: inline-block; font-size: 19px; margin-bottom: 0px; } .template-logo { display: block; margin-bottom: 40px; margin: auto; } .user-text { font-size: 18px; font-weight: 500; } .user-text span { font-weight: 600; } .text-secondary { color: #218ef4 !important } .main { background: #ffffff; border-radius: 3px; width: 100%; margin-bottom: 20px; } .wrapper { box-sizing: border-box; padding: 40px 25px; } .content-block { padding-bottom: 10px; padding-top: 10px; line-height: 2; } .footer { clear: both; text-align: center; width: 100%; } .footer td, .footer p, .footer span, .footer a { color: #999999; font-size: 12px; text-align: center; } /* ------------------------------------- TYPOGRAPHY ------------------------------------- */ h1, h2, h3, h4 { color: #000000; font-family: sans-serif; font-weight: 400; line-height: 1.4; margin: 0; Margin-bottom: 30px; } h1 { font-size: 35px; font-weight: 300; text-align: center; text-transform: capitalize; } p, ul, ol { font-family: sans-serif; font-size: 15px; font-weight: normal; margin: 0; margin-bottom: 15px; } p li, ul li, ol li { list-style-position: inside; margin-left: 5px; } a { color: #3498db; text-decoration: underline; } /* ------------------------------------- BUTTONS ------------------------------------- */ .btn { box-sizing: border-box; width: 100%; } .btn>tbody>tr>td { padding-bottom: 15px; } .btn table { width: auto; } .btn table td { background-color: #ffffff; border-radius: 5px; text-align: center; } .btn a { background-color: #ffffff; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; color: #3498db; cursor: pointer; display: inline-block; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-decoration: none; text-transform: capitalize; } .btn-primary table td { background-color: #3498db; } .btn-primary a { background-color: #3498db; border-color: #3498db; color: #ffffff; } .default-link { color: #3498db; } .default-link:hover { color: #3498db; } /* ------------------------------------- OTHER STYLES THAT MIGHT BE USEFUL ------------------------------------- */ .last { margin-bottom: 0; } .first { margin-top: 0; } .align-center { text-align: center; } .align-right { text-align: right; } .align-left { text-align: left; } .clear { clear: both; } .mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; } .preheader { color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; visibility: hidden; width: 0; } .powered-by a { text-decoration: none; } hr { border: 0; border-bottom: 1px solid #f6f6f6; Margin: 20px 0; } /* ------------------------------------- RESPONSIVE AND MOBILE FRIENDLY STYLES ------------------------------------- */ @media only screen and (max-width: 620px) { table[class=body] h1 { font-size: 28px !important; margin-bottom: 10px !important; } table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a { font-size: 16px !important; } table[class=body] .wrapper, table[class=body] .article { padding: 10px !important; } table[class=body] .content { padding: 0 !important; } table[class=body] .container { padding: 0 !important; width: 100% !important; } table[class=body] .main { border-left-width: 0 !important; border-radius: 0 !important; border-right-width: 0 !important; } table[class=body] .btn table { width: 100% !important; } table[class=body] .btn a { width: 100% !important; } table[class=body] .img-responsive { height: auto !important; max-width: 100% !important; width: auto !important; } } /* ------------------------------------- PRESERVE THESE STYLES IN THE HEAD ------------------------------------- */ @media all { .ExternalClass { width: 100%; } .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; } .apple-link a { color: inherit !important; font-family: inherit !important; font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; text-decoration: none !important; } .btn-primary table td:hover { background-color: #34495e !important; } .btn-primary a:hover { background-color: #03A9F4 !important; border-color: #03A9F4 !important; } } .btn-primary { text-decoration: none; color: #FFF; background-color: #03A9F4; border: solid #03A9F4; border-width: 6px 18px; line-height: 2em; /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ /*line-height: 28px;*/ font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 4px; text-transform: capitalize; } ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/global/templates/response/index.ts ================================================ class ResponseTemplate { static general(data) { return data; } static error(code, message, description) { return { statusCode: code || 400, message: message || 'some error occoured', description: description || 'error occoured on server, please try again after some time.' }; } static authError() { return this.error( 403, 'authentication error', 'no authentication token provided, please login first and provide the authentication token.' ); } static invalidAuthError() { return this.error( 403, 'authentication error', 'invalid Token provided, please login first and provide the authentication token.' ); } static emptyContent() { return this.general({ statusCode: 402, message: 'empty content found', description: 'you must provide valid data and it must not be empty.', helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json'] }); } static invalidContentType() { return this.general({ statusCode: 400, message: 'invalid content type', description: 'you must specify content type and it must be application/json', helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type'] }); } static routeNotFound() { return this.error( 405, 'resource not found', 'the resource your tried to access doesn\'t exist or you dont have permissions to access it.' ); } static userNotFound() { return this.error( 400, 'user not found', "the user you're looking for doesn't exist or you dont have permissions to access it." ); } static updateErrorOccoured(error) { return this.error( 301, 'error occoured', error || 'error occoured while updating your data.' ); } static success(description, data=null) { return { statusCode: 200, message: 'success', description: description || 'data successfully saved.', ...data } } } export default ResponseTemplate; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/helper/bcrypt.ts ================================================ const bcrypt = require('bcrypt-nodejs'); const jwt = require('jsonwebtoken'); const {url} = global['configuration'] const {uploadpath} = global['configuration'] const path = require('path'); const fs = require('fs'); const helper = { generateSaltValue(password) { const salt = bcrypt.genSaltSync(); // enter number of rounds, default: 10 const hash = bcrypt.hashSync(password, salt); return hash; }, comparePassword(userPassword, password ) { if (!userPassword.length || !( password && password.length > 0) ) { return false; } return bcrypt.compareSync(userPassword, password); }, authRedirectUrl( path ) { return `${url.FE}/#/auth/validate-token/${path}`; }, buildUserToken(data) { return { email: data.email, id:data._id, username: data.username ? data.username : data.email, hasPassword: data.password ? true : false, type : data.type || 1, picture : data.picture } }, resource( path ) { return `${url.API}${path}`; }, getFileExtension( file ) { let extensions = file.split('.'); if ( extensions.length === 1 ) { return 'jpg'; } else { return extensions.pop(); } }, avatarURL( filename ) { if ( filename.includes('://') ) { return filename; } return this.resource(`/${uploadpath.uploaddir}/${uploadpath.profiledir}/${filename}`); }, userDocumentURL( filename ) { if ( filename.includes('://') ) { return filename; } return this.resource(`/${uploadpath.uploaddir}/${uploadpath.documentdir}/${filename}`); }, randomString() { return Math.random().toString(36).substring(2, 7); }, deleteFile( type, filename ) { let location; if ( type === 'profile' ) { location = path.join( uploadpath.uploaddir, uploadpath.profiledir ) } else { location = uploadpath.uploaddir; } if (filename) { fs.unlink( path.join( location, filename ), () => { // in case we need to perform additional operations. }); } }, getPaymentMethodName( method ) { if ( method == 1 ) { return 'PayPal'; } else if ( method == 2 ) { return 'PayPal'; } else if ( method == 3 ) { return 'Instamojo'; } else { return 'Not Specified'; } }, getCurrency(currency) { let allCurrency = { 1: 'USD', 2: 'INR', }; if( allCurrency[currency] ) { return allCurrency[currency]; } else { return allCurrency[1]; } }, verificationCode() { let code = Math.floor((Math.random()*999999)+111111); return code; } }; export default helper; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/helper/email.ts ================================================ const path = require('path'); declare function require(name:string); const nodemailer = require('nodemailer'); const url = global['configuration'].url; const mailConfig = global['configuration'].email; import emailConfig from '../config/email'; import { EmailTemplate } from 'email-templates'; // const Twillo = require('./twillo'); const transport = nodemailer.createTransport({ host: 'smtp.gmail.com', port: 465, secure: true, auth: { // type: 'OAuth2', user: mailConfig.auth.user, pass: mailConfig.auth.pass }, }); const Email = { welcome(user) { if (user.email) { let templateDir = path.join('app/global/templates', 'emails', 'welcome-email'); let welcomeEmail = new EmailTemplate(templateDir); welcomeEmail.render({ user: user, activate_url: `${url.API}/auth/activate/${user.uuid}` }, (err, result) => { transport.sendMail( { from: emailConfig.global.from, to: user.email, subject: emailConfig.welcome.subject, html: result.html, }, (err, info) => { // some error occoured... console.log(err); } ); }); } }, password_reset(user, password) { if (user.email) { let templateDir = path.join('app/global/templates', 'emails', 'password-reset-email'); let passwordResetEmail = new EmailTemplate(templateDir); passwordResetEmail.render({ user: user, login_url: `${url.FE}/#/auth/login`, password: password }, (err, result) => { transport.sendMail( { from: emailConfig.global.from, to: user.email, subject: emailConfig.password_reset.subject, html: result.html, }, (err, info) => { // some error occoured... } ); }); } if (user.phone_verified) { // Twillo.password_reset_notification(user.phone); } }, }; export default Email; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/helper/errorHandler.ts ================================================ import * as winston from 'winston'; import ResponseTemplate from './responseTemplate'; /* eslint class-methods-use-this:0 */ const env = process.env.NODE_ENV; const onDevEnv = env === 'dev' || env === 'test' || env === 'local'; class errorHandler { public internalServerError(err, req, res, next) { winston.log('info',err); if (err.isBoom) { // Error From joi express validator const error = { message: err.output.payload.error, error: err.output.payload.message }; res.status(400).json(ResponseTemplate.BadRequestFromJoi(error)); } else { // internalServerError res.status(500).json({ success: false, message: err.message, error: (onDevEnv) ? err.stack : {} }); } } public PageNotFound(req, res, err) { res.status(404).json({ message: 'api not found' }); } } export default new errorHandler(); ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/helper/logger.ts ================================================ const winston = require('winston'); // define the custom settings for each transport (file, console) const options = { console: { level: 'info', handleExceptions: true, json: true, colorize: true, prettyPrint: true, humanReadableUnhandledException: true } }; const logger = new winston.Logger({ transports: [ // new winston.transports.File(options.file), new winston .transports .Console(options.console), ], exceptionHandlers: [ // new winston.transports.File(options.errorLog) ], exitOnError: false, // do not exit on handled exceptions }); // create a stream object with a 'write' function that will be used by `morgan` logger.stream = { write(message, encoding) { logger.info(message); } }; export default logger; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/helper/responseTemplate.ts ================================================ /* istanbul ignore file */ const data: any = { general(data) { return data; }, successMessage(message) { return { success: true, message }; }, success(data, message) { return { success: true, message, data }; }, error(message, err, code= null) { return { success: false, message: message || 'some error occurred', error: err || 'error occurred on server, please try again after some time.' }; }, emptyContent() { return this.general({ message: 'empty content found', description: 'you must provide valid data and it must not be empty.', helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json'] }); }, invalidContentType() { return this.general({ message: 'invalid content type', description: 'you must specify content type and it must be application/json', helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type'] }); }, BadRequestFromJoi(err) { return this.error( err.message, err.error ); }, userAlreadyExist(err) { return this.general({ success: false, message: 'user already registered in System', description: 'user already registered in System' }); }, userdoesNotExist(err) { return this.general({ success: false, message: err.message || 'user not registered in system', description: 'user account does not exist in system' }); }, commonAuthUserDataError() { return this.error( 'Authentication error', 'token verification failed, Please try again' ); }, tokenRequiredAuthError() { return this.error( 'Authentication error, Token is required in Header', 'token verification failed, Please try again' ); }, }; export default data; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/helper/twillo.ts ================================================ const twilioConfig = global['configuration'].twilio; // import twilio from 'twilio'; const twillo = require('twilio') const client = new twillo(twilioConfig.sid, twilioConfig.token); let TwilioHelper = { phone_verification(phone_number, code, callback) { client.sendMessage({ to: phone_number, from: twilioConfig.phone, body: `Hello from Bal Bla e-Commerce-Hub\nYour verification code is ${code}`, }, (err, message) => { callback(message); }); }, password_reset_notification(phone) { client.sendMessage({ to: phone, from: twilioConfig.phone, body: `Bla Bla\nYour password has been successfully reset.`, }, (err, message) => { // }); }, default_notification(phone, message) { console.log(client); client.sendMessage({ to: phone, from: twilioConfig.phone, body: `e-Commerce-Hub-TM\n${message}`, }, (err, message) => { // }); } } export default TwilioHelper; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/lib/logger.ts ================================================ const winston = require('winston'); const moment = require('moment'); // define the custom settings for each transport (file, console) const options = { console: { level: 'info', handleExceptions: true, json: true, colorize: true, timestamp() { return moment .utc() .format(); }, prettyPrint: true, humanReadableUnhandledException: true } }; const logger = new winston.Logger({ transports: [ // new winston.transports.File(options.file), new winston .transports .Console(options.console), ], exceptionHandlers: [ // new winston.transports.File(options.errorLog) ], exitOnError: false, // do not exit on handled exceptions }); // create a stream object with a 'write' function that will be used by `morgan` logger.stream = { write(message, encoding) { logger.info(message); } }; export default logger; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/lib/mongoose.ts ================================================ /* eslint func-names:0 */ const mongoose = require('mongoose'); mongoose.promises = require('bluebird'); const { url } = global['configuration'].mongo; const MongoConnect = function () { const db = mongoose.connect(url, { useNewUrlParser: true }, (error) => { if (error) { console.log(`Mongoose default connection error: ${error}`); } else { console.log('mongo Connected :)'); } }); mongoose.connection.on('connected', () => { console.log(`Mongoose default connection open to ${url}`); }); // If the connection throws an error mongoose.connection.on('error', (err) => { console.log(`Mongoose default connection error: ${err}`); }); // When the connection is disconnected mongoose.connection.on('disconnected', () => { console.log('Mongoose default connection disconnected'); }); // If the Node process ends, close the Mongoose connection process.on('SIGINT', () => { mongoose.connection.close(() => { console.log('Mongoose default connection disconnected through app termination'); process.exit(0); }); }); return db; }; export default MongoConnect; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/lib/requestValidator.ts ================================================ const Joi = require('joi'); const validation = { loginUser : { body : { email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), password: Joi.string().min(8).max(50).required() } }, createUser: { body: { username: Joi.string().min(4).max(50).required(), password: Joi.string().min(8).max(50).required(), email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), verify_password: Joi.string().min(6).max(50).required() }, }, resetPassword: { body: { email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), } } }; export default validation ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/middleware/authMiddleware.ts ================================================ const jwt = require("jsonwebtoken"); import responseTemplate from '../helper/responseTemplate'; import User from '../models/user'; const validation: any = { validateToken(req, res, next) { // validatr token here is its valid here const token = req.headers.authorization; if (token) { jwt.verify(token, "secretkey", (err, data) => { if (err) { res.status(403).json(responseTemplate.commonAuthUserDataError()); } else { User.findById(data.id, (error, user) => { if(error){ res.status(403).json(responseTemplate.commonAuthUserDataError()); } user.hasPassword = user.password ? true : false; req.user = user; next(); }) } }); } else { res.status(403).json(responseTemplate.tokenRequiredAuthError()); } } }; export default validation; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/middleware/requestValidator.ts ================================================ module.exports = { validatePayload(req, res, next) { // validatr token here is its valid here const token = req.body; if ((req.method === 'POST' || req.method === 'PUT') && req.body !== null) { next(); } res.status(403).json({ message: 'payload is required for HTTP Post & Put ' }); } }; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/models/plugin/plugin.ts ================================================ const datePlugin = function timestamp(schema) { // Add the two fields to the schema schema.add({ createdAt: Date, updatedAt: Date }) // Create a pre-save hook schema.pre('save', function (next) { let now = Date.now() this.updatedAt = now // Set a value for createdAt only if it is null if (!this.createdAt) { this.createdAt = now } // Call the next function in the pre-save chain next() }) } export default datePlugin; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/models/user.ts ================================================ const mongoose = require('mongoose'); const bcrypt = require('bcrypt-nodejs'); import helper from '../helper/bcrypt'; const { Schema } = mongoose; import timestampPlugin from './plugin/plugin'; import Helper from '../../app/helper/bcrypt'; const userSchema = new Schema({ provider: { type: String }, username: { type: String }, password: { type: String }, email: { index: { unique: true }, type: String }, address: { type: String }, meta: mongoose.Schema.Types.Mixed, picture : mongoose.Schema.Types.Mixed, /* reviews : [{ type: mongoose.Schema.ObjectId, ref: 'Review' }], booking : [{ type: mongoose.Schema.ObjectId, ref: 'Booking' }], vehicles: [{ type: mongoose.Schema.ObjectId, ref: 'Vehicle' }], */ uuid: { type: String }, type: { type: String, default: 1 }, status: { type: String, default: 1 }, profile_picture: mongoose.Schema.Types.Mixed, phone: String, email_verified: Boolean, phone_verified: Boolean, social: mongoose.Schema.Types.Mixed, documents: [mongoose.Schema.Types.Mixed], gender: Number, // 1: Male, 2: Female, 3: Unspecified },{ toJSON: { virtuals: true } }); userSchema.set('toObject', { virtuals: true }); userSchema.set('toJSON', { virtuals: true }); userSchema.plugin(timestampPlugin) const User = mongoose.model('User', userSchema); export default User; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/defaultRoutes.ts ================================================ import * as express from "express"; const router = express.Router(); import { Router } from "express"; export class DefaultRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public sayHello(req, res) { res.status(200).json({ success: true, message: 'i am up and running .. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️' }); }; init() { this.router.get("/", this.sayHello); } } // Create the HeroRouter, and export its configured Express.Router const defaultRouter = new DefaultRouter(); defaultRouter.init(); export default defaultRouter.router; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/provider/Facebook.ts ================================================ import * as passport from 'passport'; const FacebookStrategy = require('passport-facebook'); import userController from '../../controller/UserController'; /* eslint no-underscore-dangle: 0 */ passport.use(new FacebookStrategy( { clientID: global.configuration.facebook.client_id, clientSecret: global.configuration.facebook.client_secret, callbackURL: global.configuration.facebook.callback_url, profileFields: ['id', 'displayName', 'photos', 'email'], passReqToCallback: true, }, (req, accessToken, refreshToken, profile, done) => { const data = profile._json; if (!data.email) { data.email = 'ramnivas.yadav@srijan.net'; } userController.registerSocial({ provider: 'facebook', name: data.name, email: data.email, phone: '5436785432', meta: { provider: 'facebook', id: profile.id, token: accessToken, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); } )); const FacebookRoutes = { authenticate: () => passport.authenticate('facebook', { scope: ['email', 'public_profile', 'user_location'] }), callback: () => passport.authenticate('facebook', { failureRedirect: '/auth/failed' }) }; export default FacebookRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/provider/Google.ts ================================================ export {} const passport = require('passport'); const GoogleStrategy = require('passport-google-oauth20').Strategy; import userController from '../../controller/UserController'; /* eslint no-underscore-dangle: 0 */ passport.use(new GoogleStrategy( { clientID: global.configuration.google.client_id, clientSecret: global.configuration.google.client_secret, callbackURL: `${global.configuration.url.API}/auth/callback/google`, profileFields: ['id', 'displayName', 'photos', 'email'] }, (accessToken, refreshToken, profile, done) => { const data = profile._json; console.log(data); userController.registerSocial({ provider: 'google', username: data.displayName, email: data.emails[0].value, phone: '5436785432', picture : data.image.url, meta: { provider: 'google', id: data.id, token: accessToken, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); } )); const GoogleRoutes = { authenticate: () => passport.authenticate('google', { scope: ['profile', 'email'] }), callback: () => passport.authenticate('google', { failureRedirect: '/login' }), function(req, res) { // Successful authentication, redirect home. res.redirect('/'); } }; export default GoogleRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/provider/Linkedin.ts ================================================ export {} const passport = require('passport'); const LinkedInStrategy = require('passport-linkedin'); import userController from '../../controller/UserController'; /* eslint no-underscore-dangle: 0 */ passport.use(new LinkedInStrategy( { consumerKey: global.configuration.linkedin.client_id, consumerSecret: global.configuration.linkedin.client_secret, callbackURL: global.configuration.linkedin.callback_url, profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline'] }, ((token, tokenSecret, profile, done) => { console.log(profile); const data = profile._json; userController.registerSocial({ provider: 'linkedin', name: `${data.firstName} ${data.lastName}`, email: data.emailAddress, mobno: '5436785432', meta: { provider: 'linkedin', id: data.id, token, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); }) )); const LinkedinRoutes = { authenticate: () => passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }), callback: () => passport.authenticate('linkedin', { failureRedirect: '/auth/failed' }) }; export default LinkedinRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/provider/Locale.ts ================================================ /* eslint prefer-destructuring:0 */ const passportModule = require('passport'); const LocalStrategy = require('passport-local'); import userController from '../../controller/UserController'; const User = require('../../models/user'); const helper = require('../../helper/bcrypt'); passportModule.use(new LocalStrategy( { usernameField: 'email', passwordField: 'password', passReqToCallback: true, session: false }, ((req, email, password, done) => { // write code here to find user if it exists in system User.find({ email }, (err, data) => { if (err) { return done(null, null); } else if (data.length === 0) { return done(null, null); } const flag = helper.comparePassword(password, data[0].password); if (!flag) { return done(null, null); } return done(null, data); }); }) )); const localRoutes = { authenticate() { return passportModule.authenticate('local', { session: false }); }, authenticate_with_callback: () => passportModule.authenticate('local', { successRedirect: '/auth/success', failureRedirect: '/auth/failed' }), }; export default localRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/provider/Twitter.ts ================================================ const passport = require('passport'); const TwitterStrategy = require('passport-twitter').Strategy; import userController from '../../controller/UserController'; passport.use(new TwitterStrategy( { consumerKey: global.configuration.twitter.client_id, consumerSecret: global.configuration.twitter.client_secret, callbackURL: 'http://127.0.0.1:3005/auth/callback/twitter' }, (token, tokenSecret, profile, done) => { console.log('data>>>', profile); const data = profile; userController.registerSocial({ provider: 'twitter', username: data.username, email: data.email || 'raam.yaadav@gmail.com', mobno: '5436785432', meta: { provider: 'twitter', id: data.id, token, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); } )); const TwitterRoutes = { authenticate: () => passport.authenticate('twitter'), callback: () => passport.authenticate('twitter', { failureRedirect: '/auth/failed' }), function(req, res) { // Successful authentication, redirect home. res.redirect('/'); } }; export default TwitterRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/routes.ts ================================================ import * as express from "express"; import UserController from "../controller/UserController"; const jwt = require("jsonwebtoken"); // seralize user Object const url = global['configuration'].url; import LocaleRoute from "./provider/Locale"; import * as expressJoiValidator from "express-joi-validator"; import expressJoi from "../lib/requestValidator"; // import FacebookRoutes from "./provider/Facebook"; import GoogleRoutes from "./provider/Google"; // import LinkedinRoutes from "./provider/Linkedin"; import Template from "../helper/responseTemplate"; // import TwitterRoute from "./provider/Twitter"; import * as template from '../helper/responseTemplate'; const boom = require("express-boom"); import { Router, Request, Response, NextFunction } from "express"; import helper from '../helper/bcrypt'; import ValidAuthTokenMiddleware from '../middleware/authMiddleware'; export class AuthRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); this.init(); } public register(req: any, res: any) { UserController.registerDefault(req, res, (error, user) => { if (error) { res.status(400).json(Template.userAlreadyExist(error.message)); } else { res.json({ statusCode: 200, success: true, message: "user created successfully", user }); } }); } public login(req: any, res: any) { UserController.validateUser(req, res, (err, token) => { if (err) { res.status(401).json(Template.userdoesNotExist(err)); } else { res.status(200).json({ success: true, message: "success", token }); } }); } public redirectSocialUser(req, res) { jwt.sign(helper.buildUserToken(req.user), "secretkey", (tokError, token) => { if (tokError) { res.boom.badImplementation(tokError); } else { // redirect app to FE app routes with Token console.log('redirecting Now...'); res.redirect(helper.authRedirectUrl(`?token=${token}`)); /* res.json({ statusCode: 200, message: "success", token }); */ } }); } public validate(req: any, res: any) { res.json({ statusCode: 200, message: 'validated succsessfully', success: true, user : req.user }); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public resetPassword(req, res) { UserController.resetPassword(req.body.email, (error, success) => { console.log(error) if (error) { res.status(403).json({ success: false, message: error, description: 'error occoured while resetting password' }); } else { res.json({ statusCode: 200, message: 'success', description: 'if this email is registered with us, you will receive a password reset email soon.', }); } }); }; public activateUserAccount(req, res) { UserController.activateUserAccount(req.params.uuid, (error, success) => { if (error) { res.status(403).json({ success: false, message: error, description: 'error occoured while activating user' }); } else { res.redirect(url.FE); } }); } /** * Take each handler, and attach to one of the Express.Router's * endpoints. */ init() { this.router.post("/login", expressJoiValidator(expressJoi.loginUser), this.login); this.router.get("/validate", ValidAuthTokenMiddleware.validateToken, this.validate); this.router.post("/register", expressJoiValidator(expressJoi.createUser), this.register); this.router.post("/reset-password", expressJoiValidator(expressJoi.resetPassword), this.resetPassword); this.router.get("/activate/:uuid", this.activateUserAccount); /** * @api {POST} /auth/login/facebook Social Login * @apiName google * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ /* this.router.get("/login/facebook", FacebookRoutes.authenticate()); this.router.get( "/callback/facebook", FacebookRoutes.callback(), this.redirectSocialUser ); */ /** * @api {POST} /auth/login/google Social Login * @apiName google * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ this.router.get("/login/google", GoogleRoutes.authenticate()); this.router.get( "/callback/google", GoogleRoutes.callback(), this.redirectSocialUser ); /** * @api {POST} /auth/login/twitter Social Login * @apiName twitter * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ /*this.router.get("/login/twitter", TwitterRoute.authenticate("twitter")); this.router.get( "/callback/twitter", TwitterRoute.callback(), this.redirectSocialUser ); */ /** * @api {POST} /auth/login/linkedin Social Login * @apiName linkedin * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ /* this.router.get("/login/likedin", LinkedinRoutes.authenticate()); this.router.get("/login/linkedin", LinkedinRoutes.authenticate()); this.router.get( "/callback/linkedin", LinkedinRoutes.callback(), this.redirectSocialUser ); */ } } // Create the HeroRouter, and export its configured Express.Router const authRoutes = new AuthRouter(); authRoutes.init(); export default authRoutes.router; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes/userRoutes.ts ================================================ import * as express from "express"; const router = express.Router(); const passport = require("passport"); import UserController from "../controller/UserController"; const jwt = require("jsonwebtoken"); // seralize user Object import ResponseTemplate from '../global/templates/response'; import * as expressJoiValidator from "express-joi-validator"; import expressJoi from "../lib/requestValidator"; const boom = require("express-boom"); import { Router } from "express"; const path = require('path') const fs = require('fs'); const { uploadpath } = global['configuration'] const multer = require('multer'); import Helper from '../helper/bcrypt'; let profileStorage = multer.diskStorage({ destination: function (req, file, cb) { cb( null, path.join( uploadpath.uploaddir, uploadpath.profiledir ) ); }, filename: function (req, file, cb) { let extension = Helper.getFileExtension(file.originalname); cb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` ); } }) let upload = multer({ storage: profileStorage }); let documentStorage = multer.diskStorage({ destination: function (req, file, cb) { cb( null, path.join( uploadpath.uploaddir, uploadpath.documentdir ) ); }, filename: function (req, file, cb) { let extension = Helper.getFileExtension(file.originalname); cb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` ); } }) let uploadDocuments = multer({ storage: documentStorage }); export class AuthRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); this.init(); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public resetPassword(req, res){ UserController.resetPassword( req.body.email, ( error, success) => { console.log(error) if ( error ) { res.status(403).json({success : false, message: error, description: 'error occoured while resetting password' }); } else { res.json({ statusCode: 200, message: 'success', description: 'if this email is registered with us, you will receive a password reset email soon.', }); } }); }; public updateUser(req, res){ UserController.updateUser(req.params.email, req.body ,( error, success) => { if ( error ) { res.status(403).json({success : false, message: error, description: 'error occoured while updating user' }); } else { res.json({ statusCode: 200, message: 'success', description: 'user updated successfully', }); } }); } public getUserByEmail(req, res){ UserController.getUserByEmail(req.params.email ,( error, user) => { if ( error ) { res.status(403).json({success : false, message: error, description: 'error occoured while updating user' }); } else { res.json({ statusCode: 200, message: 'success', data: user }); } }); } public uploadProfilepicture(req, res){ UserController.updateUser( req.user.email, { picture: req.file.filename }, ( error, user ) => { if ( error ) { res.json( ResponseTemplate.updateErrorOccoured(error) ); } else { res.json( ResponseTemplate.success( 'your profile picture has been successfully uploaded', { picture: Helper.avatarURL(user.picture) }) ); Helper.deleteFile( 'profile', req.user.picture ); } }); } // upload users profile picture. public uploadDocuments(req, res){ let documents:any = {}; req.files.map( (file) => { documents.url = file.filename; documents.originalname = file.originalname; documents.timestamp = new Date(); }); UserController.updateUser( req.user.email, { document: documents }, ( error, user ) => { if ( error ) { res.json( ResponseTemplate.updateErrorOccoured(error) ); } else { let userDocuments = []; if ( user.documents ) { user.documents.map( (doc) => { userDocuments.push( Helper.userDocumentURL(doc.url) ); }); } res.json( ResponseTemplate.success( 'host documents have been successfully uploaded', { documents: userDocuments }) ); } }); } /** * Take each handler, and attach to one of the Express.Router's * endpoints. */ init() { this.router.get("/:email", this.getUserByEmail); this.router.get("/reset-password/:email",expressJoiValidator(expressJoi.resetPassword), this.resetPassword); this.router.put("/update/:email", this.updateUser); this.router.post('/upload-profile-picture', upload.single('avatar'), this.uploadProfilepicture); this.router.post('/upload-documents', uploadDocuments.array('documents'), this.uploadDocuments); } } // Create the HeroRouter, and export its configured Express.Router const authRoutes = new AuthRouter(); authRoutes.init(); export default authRoutes.router; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/routes.ts ================================================ /* eslint func-names: ["error", "never"] */ /* eslint prefer-destructuring: 0 */ import * as express from 'express'; const expressRouter= express.Router(); import authRoutes from './routes/routes'; import userRoutes from './routes/userRoutes'; import defaultRoutes from './routes/defaultRoutes'; import validAuthTokenMiddleware from './middleware/authMiddleware'; expressRouter.use('/', defaultRoutes); expressRouter.use('/uploads/', express.static('uploads')); expressRouter.use('/auth', authRoutes); expressRouter.use('/user',validAuthTokenMiddleware.validateToken, userRoutes); export default expressRouter; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/seed/seedUsers.ts ================================================ import User from '../models/user'; const mongoose = require('mongoose'); const dbName = 'blabla'; mongoose.connect(`mongodb://localhost/${dbName}`); /* eslint quote-props:0 */ /* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */ const users = [ { 'username': 'tarun', 'email': 'tarun@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1222@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun22@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun5@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun6@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'asdfg@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tgfdsa@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarunfgds8@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'asdfcv@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'dekoo@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'hellodemo@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'gmail@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 16.5377266, 'lng': 79.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' } ]; User.collection.drop(); User.create(users, (err) => { if (err) { throw (err); } console.log(`Created ${users.length} User`); mongoose.connection.close(); }); /* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal: node ./bin/seeds.js. De esta manera se crea la base de datos */ ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/seed/seedVehicle.ts ================================================ import User from '../models/user'; const mongoose = require('mongoose'); const dbName = 'blabla'; mongoose.connect(`mongodb://localhost/${dbName}`); /* eslint quote-props:0 */ /* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */ const users = [ { 'username': 'tarun', 'email': 'tarun@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1222@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun22@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun5@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun6@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun7@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun8@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' } ]; User.collection.drop(); User.create(users, (err) => { if (err) { throw (err); } console.log(`Created ${users.length} User`); mongoose.connection.close(); }); /* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal: node ./bin/seeds.js. De esta manera se crea la base de datos */ ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/transformer/userTransformer.ts ================================================ 'use strict'; import _ from 'lodash'; // import ReviewTransformer from './ReviewTransformer'; let UserTransformer = { xx : (users) =>{ if ( Array.isArray(users) ) { let output = []; users.forEach(( user ) => { output.push( UserTransformer._transformUsers(user) ); }); return output; } else { return UserTransformer._transformUsers(users); } }, transform: (users) => { if (Array.isArray(users)) { let output = []; users.forEach((user) => { output.push(UserTransformer._transform(user)); }); return output; } else { return UserTransformer._transform(users); } }, calculateUsers: (users: any | null) => { if (Array.isArray(users)) { return { Users : users.length ? users.length : 100, vehicles : (users['vehicle'] ) ? users['vehicle'].length : 1000, cities :100 } } }, _transform: (user) => { if (!user) { return {}; } let user_status = (user.status === 1) ? 'active' : 'disabled'; return { id: user._id, username : user.username, status: user_status, name: user.name, email: user.email, password: (user.password) ? true : false, phone: user.phone || '', gender: user.gender || '', birthday: user.birthday || '', type: user.type || 1, meta: user.meta || {}, social : user.social || [], phone_verified: user.phone_verified ? true : false, email_verified: user.email_verified ? true : false, profile_picture: user.profile_picture ? null : null // will fix later }; }, transformUsers: ( users ) => { if ( Array.isArray(users) ) { let output = []; users.forEach(( user ) => { output.push( UserTransformer._transformUsers(user) ); }); return output; } else { return UserTransformer._transformUsers(users); } }, _transformUsers: ( user ) => { if ( ! user ) { return {}; } let user_status = ( user.status === '1' ) ? 'active' : 'disabled'; const obj:any = {}; return Object.assign({}, { id: user._id, username : user.username, status: user_status, name: user.name, email_verified:user.email_verified, phone_verified :user.phone_verified, reviews : user.reviews, vehciles : user.vehciles, email: user.email, date : user.createdAt, type: user.type || 1, }, obj); } } export default UserTransformer; ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/types/global.d.ts ================================================ declare namespace NodeJS { export interface Global { configuration: any } } ================================================ FILE: dockerized-containers/e-Commerce-Admin/app/types/vendor.d.ts ================================================ declare namespace NodeJS { export interface Global { configuration: any } } ================================================ FILE: dockerized-containers/e-Commerce-Admin/env.sh ================================================ # this environment vairables needs to be set in .env file in applciaiton root directory # copy this file as .env and add the appropriate values as per environment. # node & mysql export NODE_ENV="dev" export PORT="3002" export MONGOURL="mongodb://ms_commerce_mongo/blabla" export EXPRESS_SESSION_SECRET="######################" export F_CLIENTID="###################" export F_CLIENTSECRET="###########################" export F_CALLBACK="/auth/callback/facebook" export G_CLIENTID="@@@@@@@@@@@@@-###############.apps.%%%%%%%%%%%.com" export G_CLIENTSECRET="k##########@@@@@@@@@@@@Ub" export G_CALLBACK="/auth/callback/google" export L_CLIENTID="##################" export L_CLIENTSECRET="############" export L_CALLBACK="/auth/callback/linkedin" export T_CLIENTID="##################" export T_CLIENTSECRET="######################" export T_CALLBACK="/auth/callback/twitter" export FE_URL="localhost:3000" export API_KEY='XX0xxxxx-xX0X0XxXXxXxXXXxX0x' export SMTP_HOST='smtp.mandrillapp.com' export SMTP_PORT='587' export SMTP_USER='#############.net' export SMTP_PASSWORD='##############' export SID='XX0xxxxx-xX0X0XxXXxXxXXXxX0x' export TOKEN='XX0xxxxx-xX0X0XxXXxXxXXXxX0x' export PHONE='+9716156786' export FE='http://localhost:3000' export API='http://localhost:3005' export UPLOAD_DIR='uploads' export PROFILE_PICTURE_DIR='profile' export DOCUMENT_UPLOAD_DIR='documents' ================================================ FILE: dockerized-containers/e-Commerce-Admin/express.ts ================================================ import router from './app/routes'; import * as boom from 'express-boom'; import * as expressSession from 'express-session'; import * as cookieParser from 'cookie-parser'; import * as passport from 'passport'; import * as helmet from 'helmet'; import * as cors from 'cors'; import * as path from 'path'; import * as express from 'express'; import * as logger from 'morgan'; import * as bodyParser from 'body-parser'; import errorHandlers from './app/helper/errorHandler'; // Creates and configures an ExpressJS web server. class App { // ref to Express instance public express: express.Application; //Run configuration methods on the Express instance. constructor() { this.express = express(); this.middleware(); this.routes(); } // Configure Express middleware. private middleware(): void { this.express.use(passport.initialize()); // required for passport to initlize it this.express.use(expressSession({ secret: 'bla bla' })); this.express.use(passport.session()); // initlize session this.express.use(logger('dev')); this.express.disable('x-powered-by'); this.express.disable('etag'); this.express.use(helmet()); this.express.use(boom()); this.express.use(helmet.noCache({ noEtag: true })); // set Cache-Control header this.express.use(helmet.noSniff()); // set X-Content-Type-Options header this.express.use(helmet.frameguard()); // set X-Frame-Options header this.express.use(helmet.xssFilter()); // set X-XSS-Protection header // logger logs on console this.express.use(bodyParser.urlencoded({ extended: false, limit: '5mb' })); // parse application/x-www-form-urlencoded this.express.use(bodyParser.json()); // parse application/json // enable CORS this.express.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PATCH, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, api_key, Authorization, Referer'); next(); }); // register all custom Middleware this.express.use(cors({ optionsSuccessStatus: 200 })); this.express.use(cookieParser()); // cookies-parser // manage session by cookies this.express.set('views', path.join(__dirname, 'views')); // setting views this.express.set('view engine', 'hbs'); // server side template rendering this.express.use(express.static(path.join(__dirname, 'public'))); this.express.use(logger('dev')); this.express.use(bodyParser.json()); this.express.use(bodyParser.urlencoded({ extended: false })); } // Configure API endpoints. private routes(): void { passport.serializeUser((user, done) => { done(null, user); }); passport.deserializeUser((user, done) => { done(null, user); }); /* This is just to get up and running, and to make sure what we've got is * working so far. This function will change when we start to add more * API endpoints */ this.express.use('/api/v1', router); this.express.use(errorHandlers.internalServerError); this.express.use(errorHandlers.PageNotFound); } } export default new App().express; ================================================ FILE: dockerized-containers/e-Commerce-Admin/package.json ================================================ { "name": "e-commerce-hub", "version": "0.0.0", "private": true, "scripts": { "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "startdev": ". ./env.sh && cd dist && nodemon server.js", "clean": "rm -rf dist", "watch": "tsc", "copy": "cp -r uploads dist/", "test": ". ./env.sh && NODE_ENV=test && mocha ", "debug": ". ./env.sh && NODE_ENV=test && cd dist && nodemon --inspect=0.0.0.0:9230 server.js", "prestartdev": " npm run clean && tsc && npm run copy && npm run watch", "watchserver" : "tsc --watch", "dev": ". ./env.sh && ts-node server.ts", "start-tsc": ". ./env.sh && nodemon ./dist/server.js", "buildAndstart": ". ./env.sh && npm run build && npm run start" }, "dependencies": { "@types/express": "^4.11.1", "assert": "^1.4.1", "axios": "^0.18.0", "bcrypt-nodejs": "0.0.3", "bluebird": "^3.5.3", "body-parser": "^1.18.3", "cookie-parser": "^1.4.3", "cors": "^2.8.5", "dotenv": "^6.1.0", "email-templates": "^2.7.1", "express": "^4.16.4", "express-boom": "^2.0.0", "express-joi-validator": "^2.0.0", "express-session": "^1.15.6", "fast-csv": "^2.4.1", "hbs": "^4.0.1", "helmet": "^3.15.0", "joi": "^14.1.1", "jsonwebtoken": "^8.4.0", "mocha": "^5.2.0", "moment": "^2.22.2", "mongoose": "^4.5.9", "morgan": "^1.9.0", "multer": "^1.2.0", "nodemailer": "2.5.0", "nodemon": "^1.18.6", "passport": "0.3.2", "passport-facebook": "2.1.1", "passport-google-oauth": "1.0.0", "passport-google-oauth20": "^1.0.0", "passport-instagram": "1.0.0", "passport-linkedin": "^1.0.0", "passport-local": "1.0.0", "passport-twitter": "1.0.4", "pug": "2.0.0-beta6", "serve-favicon": "^2.5.0", "ts-lint": "^4.5.1", "ts-node": "^7.0.1", "twilio": "^2.11.1", "typescript": "^3.1.6", "uuid": "^3.3.2", "winston": "^2.4.2" }, "devDependencies": { "@types/async": "^2.0.45", "@types/bcrypt-nodejs": "^0.0.30", "@types/bluebird": "^3.5.20", "@types/body-parser": "^1.16.8", "@types/express": "^4.11.1", "@types/mongoose": "^4.7.34", "@types/morgan": "^1.7.35", "@types/node": "^9.6.39", "@types/nodemailer": "^4.3.4", "@types/passport": "^0.4.3", "babel-eslint": "^8.0.1", "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.9.0", "eslint-plugin-node": "^5.2.1" } } ================================================ FILE: dockerized-containers/e-Commerce-Admin/public/javascripts/script.js ================================================ document.addEventListener('DOMContentLoaded', () => { console.log('IronGenerator JS imported successfully!'); }, false); ================================================ FILE: dockerized-containers/e-Commerce-Admin/public/style.scss ================================================ body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; } a { color: #00B7FF; } .h1 { font-size: 40px; } ================================================ FILE: dockerized-containers/e-Commerce-Admin/server.ts ================================================ import * as http from 'http'; import * as debug from 'debug'; // After you declare "app" const env = process.env.NODE_ENV || 'dev' console.log(` using ${process.env.NODE_ENV} to run application`); global.configuration = require(`./app/config/environments/${env}`); import App from './express'; const port = (process.env.PORT); const logger = require('winston'); import mongoose from './app/lib/mongoose'; mongoose(); const server = http.createServer(App); server.listen(process.env.PORT); server.on('error', onError); server.on('listening', onListening); function onError(error: NodeJS.ErrnoException): void { if (error.syscall !== 'listen') throw error; let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port; switch(error.code) { case 'EACCES': console.error(`${bind} requires elevated privileges`); process.exit(1); break; case 'EADDRINUSE': console.error(`${bind} is already in use`); process.exit(1); break; default: throw error; } } const gracefulStopServer = function () { // Wait 10 secs for existing connection to close and then exit. setTimeout(() => { logger.info('Shutting down server'); process.exit(0); }, 1000); }; process.on('uncaughtException', (err) => { logger.error(err, 'Uncaught exception'); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { logger.error({ promise, reason }, 'unhandledRejection'); process.exit(1); }); process.on('SIGINT', gracefulStopServer); process.on('SIGTERM', gracefulStopServer); function onListening(): void { let addr = server.address(); let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`; debug(`Listening on ${bind}`); } ================================================ FILE: dockerized-containers/e-Commerce-Admin/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "moduleResolution": "node", "pretty": true, "sourceMap": true, "target": "es6", "outDir": "./dist", "experimentalDecorators": false, "emitDecoratorMetadata": false, "skipDefaultLibCheck": false, "baseUrl": "./lib" }, "files" : [ "./app/types/vendor.d.ts" ], "include": [ "/**/*.ts" ], "exclude": [ "node_modules" ] } ================================================ FILE: dockerized-containers/e-Commerce-Admin/tslint.json ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Admin/uploads/documents/.gitkeep ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Admin/uploads/profile/.gitkeep ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Auth/Dockerfile ================================================ FROM node:carbon # Create app directory WORKDIR /usr/src/app # Bundle app source COPY . . # npm install RUN npm install EXPOSE 3001 9201 CMD [ "npm", "run", "watchserver" ] CMD [ "npm", "run", "startdev" ] ================================================ FILE: dockerized-containers/e-Commerce-Auth/README.md ================================================ # Application for e-commerce Hub REST API to support application features - Express as web framework with Typescript - Passport js for social authentication - Express CORS enabled - boom for error codes & Joi for Validation - Winston for logging and express minitor for monitoring - Mongoose as ODM driver - eslint validation extending airbnb styleguide - git hooks & CI/CD in place - Typescript based compilation tsc compiler - TDD in progress with Mocha - JWT based authentication - multiple Mongoose collection with referencing - payment gateway Integration - Heroku deployment - Mini e-commerce platform # Cart Application # "It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills ``` # Application Execution ```javascript git clone repo npm install npm run startdev tsc -- watch ``` # Application configuration ```javascript env.sh need to be added locally export NODE_ENV="dev" export PORT="3005" export MONGOURL="mongodb://mongo/hello" export EXPRESS_SESSION_SECRET="************************" export F_CLIENTID="**************" export F_CLIENTSECRET="**********************" ``` # Application NPM Script ```javascript "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "clean" : "rm -rf dist", "copy" : "cp -r uploads dist/ && cp -r app/global dist/app/" ``` ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/config/email.ts ================================================ 'use strict'; export default { global: { from: 'info@kpilibrary.com', }, welcome: { subject: 'Welcome to KPI Library', }, password_reset: { subject: 'KPI Library: Reset your password', }, event_booked_guest: { subject: 'KPI Library: Your Booking Has Been Confirmed', }, event_booked_host: { subject: 'KPI Library: Your Event Has Been Booked', }, event_booked_guests_notification: { subject: 'KPI Library: Your Booking Has Been Confirmed', }, message_received: { subject: 'KPI Library: New Message Received', }, guest_review_email: { subject: 'KPI Library: Event Completed', }, alacarte_booked_guest: { subject: 'KPI Library: Alacarte Booking Details', }, alacarte_booked_host: { subject: 'KPI Library: Your Alacarte Has Been Booked', } } ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/config/environments/dev.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.db = { mysql: { user: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, connectTimeout: 100000 }, mongo: { host: process.env.MONGO_HOST, port: process.env.MONGO_PORT, uername: process.env.MONGO_USERNAME, password: process.env.MONGO_PASSWORD, database: process.env.MONGO_DATABASE } }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/config/environments/qa.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/config/environments/test.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/controller/UserController.ts ================================================ const uuidv4 = require('uuid/v4'); import User from '../models/user'; declare function require(name: string); import Helper from '../helper/bcrypt'; const jwt = require('jsonwebtoken'); import helper from '../helper/bcrypt'; import mailEvents from '../events/notification'; import logger from '../helper/logger'; import email from '../helper/email'; const saltRounds = 10; class userController { static getUserByEmail(email, cb) { User.findOne({ 'email': email }, (error, user) => { if (user) { cb(null, user); } else { cb('User does not exist in system', null); } }); } static validateUser(req, res, cb) { const { body } = req; User.find({ email: body.email }) .then((data) => { if (data && data.length) { const flag = helper.comparePassword(body.password, data[0].password) if (flag) { jwt.sign(helper.buildUserToken(data[0]), 'secretkey', (tokError, token) => { cb(null, token); }); } else { cb(new Error('username password does not match'), null); } } else { cb(new Error('no user found with this account email'), null); } }).catch((err)=>{ console.log(err); cb(new Error('no user found with this account email'), null); }) } static registerDefault(req, res, cb) { const { body } = req; const { location } = req; const hash = helper.generateSaltValue(body.password); return User.find({ email: body.email }).then((user) => { if (user && user.length > 0) { cb(new Error('user already regitsered with us'), null); } else { return User.create(this.buildUser(body, hash, location) , (error, user) => { if (error) { cb(error, null); } else { logger.info('emitting user create event'); mailEvents.emit("welcome", user); cb(null, user); } }); } }); } static buildUser(body, hash = null, location = null) { const build = { username: body.username, phone: body.phone, email: body.email, email_verified: false, phone_verified: false, picture: body.picture ? body.picture : null, status: 1, gender: null, documents: [], type: 1, social: body.meta, uuid: uuidv4() } return hash ? Object.assign({}, build, { password: hash }) : build; } static registerSocial(user, callback) { User.findOne({ email: user.email }, (error, existingUser) => { if (existingUser) { callback(null, (existingUser)); } else { User.create(this.buildUser(user, null), (err, user) => { if (err) { callback(err, null); } else { callback(null, user); mailEvents.emit("welcome", user); } }); } }); } static activateUserAccount(uuid, cb) { User.findOne({ 'uuid': uuid }, (error, foundUser) => { if (foundUser) { foundUser.email_verified = true; foundUser.save(function (err) { if (err) { cb('error occoured while updating record'); } else { cb(null, 'done'); } }); } else { cb('User does not exist in system'); } }); } static resetPassword(email, callback) { // just generate password and send new password on mail User.findOne({ 'email': email }, (error, foundUser) => { if (foundUser) { let password = Math.random().toString(36).slice(2); const hash = helper.generateSaltValue(password); foundUser.password = hash; foundUser.save(function (err) { if (err) { callback('error occoured while updating record'); } else { mailEvents.emit("forgotPassword", foundUser, password); callback(null, 'done'); } }); } else { callback('User does not exist in system with this email'); } }); } static changeUserRole(req, callback) { const email = req.params.email const body = req.body User.findOne({ 'email': email }, (error, user) => { if (user) { user.type = 2; user.save(function (err, updated_user) { if (err) { callback('error occoured while chaging role'); } else { callback(null, updated_user); } }); } else { callback('user not found in system', null); } }); } static updateUser(email, data, callback) { User.findOne({ 'email': email }, (error, user) => { if (user) { if (data.username) { user.username = data.username; } if (data.gender) { user.gender = data.gender; } if (data.phone) { user.phone = data.phone; } if (data.profile_picture) { user.profile_picture = data.profile_picture; } if (data.password && data.password === data.confirm_password) { const hash = helper.generateSaltValue(data.password); user.password = hash; } if ( data.picture ) { user.picture = Helper.avatarURL(data.picture) } if (data.phone_verified) { user.phone_verified = true; } if (data.document) { user.documents.push(data.document); } if (data.meta) { user.meta = { about: data.meta.about || '', fun_fact: data.meta.fun_fact || '', payment: data.meta.payment || '', } } user.save(function (err, updated_user) { if (err) { callback('error occoured while updating record'); } else { callback(null, updated_user); } }); } else { callback('user not found', null); } }); } } export default userController; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/events/notification.ts ================================================ import Email from '../helper/email'; declare function require(name: string); const events = require('events'); const winston = require('winston'); // import Twillo from '../helper/twillo'; const eventEmitter = new events.EventEmitter(); eventEmitter.on('welcome', (user) => { winston.log('info', `sending welcome email to ${user.email}`); // Twillo.default_notification(user.phone, 'welcome') Email.welcome(user); }); eventEmitter.on('forgotPassword', (user, password, uuid) => { winston.log('info', `sending forgotPassword email to ${user.email}`); Email.password_reset(user, password); // Twillo.default_notification(user.phone, 'welcome') }); export default eventEmitter; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/global/templates/emails/password-reset-email/html.pug ================================================ html(lang='en') head meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') title password has successfully been reset link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet') link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico') link(rel='stylesheet', href='../assets/styles/style.css', type='text/css') body(data-gr-c-s-loaded='true', style='') .template-wrapper table.body(border='0', cellpadding='0', cellspacing='0') tbody tr td   td.container .content table.main tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td a.template-logo(href='../index.html') img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='') p.lead | Hello #{user.email}, br | Your password has successfully been reset table(border='0', cellpadding='0', cellspacing='0') tbody tr td.mt30.mb30(align='center') table(border='0', cellpadding='0', cellspacing='0') tbody tr td p.user-text span Your new password is #[pre #{password}] br a.btn-primary(href= login_url) Login p Thank you p.mb0 | If you have any problems, please contact me at a.click-link(href='#') admin@gmail.com table.help-section tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td h2.text-center.mb0 Need more help? a.support-link(href='#') We're here,ready to here table tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td p | You received this email beacuse you just signed up for new account. If it look weird a.default-link(href='#') view it in your browser .footer table(border='0', cellpadding='0', cellspacing='0') tbody tr td.content-block p.text-center | © 2018 KPI App, Goa India br | If these emails get annoying, please feel to a(href='#') unsubscribe td   ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/global/templates/emails/password-reset-email/style.css ================================================ @charset "UTF-8"; /* ------------------------------------- GLOBAL RESETS ------------------------------------- */ .container { display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } img { border: none; -ms-interpolation-mode: bicubic; max-width: 100%; } body { background-color: #f6f6f6; font-family: 'Rubik', sans-serif; font-size: 15px; line-height: 28px; -webkit-font-smoothing: antialiased; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } table { border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; } table td { font-family: sans-serif; font-size: 14px; vertical-align: top; } /* ------------------------------------- BODY & CONTAINER ------------------------------------- */ .body { background-color: #f6f6f6; width: 100%; } .lead { font-size: 18px; } .mt30 { margin-top: 30px; display: block; } .mb30 { margin-bottom: 30px; display: block; } /* 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 */ .container { display: block; Margin: 0 auto !important; /* makes it centered */ max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } /* This should also be a block element, so that it will fill 100% of the .container */ .content { box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; } /* ------------------------------------- HEADER, FOOTER, MAIN ------------------------------------- */ .template-wrapper { background-color: #03A9F4; width: 100%; height: 250px; position: relative; } .click-link { color: #03A9F4; display: inline-block; margin-bottom: 20px; } .help-section { background-color: #ffdcdc; border-radius: 3px; width: 100%; text-align: center; } .mb0 { margin-bottom: 0px; } .support-link { color: #03A9F4; display: inline-block; font-size: 19px; margin-bottom: 0px; } .template-logo { display: block; margin-bottom: 40px; margin: auto; } .user-text { font-size: 18px; font-weight: 500; } .user-text span { font-weight: 600; } .text-secondary { color: #218ef4 !important } .main { background: #ffffff; border-radius: 3px; width: 100%; margin-bottom: 20px; } .wrapper { box-sizing: border-box; padding: 40px 25px; } .content-block { padding-bottom: 10px; padding-top: 10px; line-height: 2; } .footer { clear: both; text-align: center; width: 100%; } .footer td, .footer p, .footer span, .footer a { color: #999999; font-size: 12px; text-align: center; } /* ------------------------------------- TYPOGRAPHY ------------------------------------- */ h1, h2, h3, h4 { color: #000000; font-family: sans-serif; font-weight: 400; line-height: 1.4; margin: 0; Margin-bottom: 30px; } h1 { font-size: 35px; font-weight: 300; text-align: center; text-transform: capitalize; } p, ul, ol { font-family: sans-serif; font-size: 15px; font-weight: normal; margin: 0; margin-bottom: 15px; } p li, ul li, ol li { list-style-position: inside; margin-left: 5px; } a { color: #3498db; text-decoration: underline; } /* ------------------------------------- BUTTONS ------------------------------------- */ .btn { box-sizing: border-box; width: 100%; } .btn>tbody>tr>td { padding-bottom: 15px; } .btn table { width: auto; } .btn table td { background-color: #ffffff; border-radius: 5px; text-align: center; } .btn a { background-color: #ffffff; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; color: #3498db; cursor: pointer; display: inline-block; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-decoration: none; text-transform: capitalize; } .btn-primary table td { background-color: #3498db; } .btn-primary a { background-color: #03A9F4; border-color: #03A9F4; color: #ffffff; } .default-link { color: #03A9F4; } .default-link:hover { color: #03A9F4; } /* ------------------------------------- OTHER STYLES THAT MIGHT BE USEFUL ------------------------------------- */ .last { margin-bottom: 0; } .first { margin-top: 0; } .align-center { text-align: center; } .align-right { text-align: right; } .align-left { text-align: left; } .clear { clear: both; } .mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; } .preheader { color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; visibility: hidden; width: 0; } .powered-by a { text-decoration: none; } hr { border: 0; border-bottom: 1px solid #f6f6f6; Margin: 20px 0; } /* ------------------------------------- RESPONSIVE AND MOBILE FRIENDLY STYLES ------------------------------------- */ @media only screen and (max-width: 620px) { table[class=body] h1 { font-size: 28px !important; margin-bottom: 10px !important; } table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a { font-size: 16px !important; } table[class=body] .wrapper, table[class=body] .article { padding: 10px !important; } table[class=body] .content { padding: 0 !important; } table[class=body] .container { padding: 0 !important; width: 100% !important; } table[class=body] .main { border-left-width: 0 !important; border-radius: 0 !important; border-right-width: 0 !important; } table[class=body] .btn table { width: 100% !important; } table[class=body] .btn a { width: 100% !important; } table[class=body] .img-responsive { height: auto !important; max-width: 100% !important; width: auto !important; } } /* ------------------------------------- PRESERVE THESE STYLES IN THE HEAD ------------------------------------- */ @media all { .ExternalClass { width: 100%; } .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; } .apple-link a { color: inherit !important; font-family: inherit !important; font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; text-decoration: none !important; } .btn-primary table td:hover { background-color: #34495e !important; } .btn-primary a:hover { background-color: #03A9F4 !important; border-color: #03A9F4 !important; } } .btn-primary { text-decoration: none; color: #FFF; background-color: #03A9F4; border: solid #03A9F4; border-width: 6px 18px; line-height: 2em; /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ /*line-height: 28px;*/ font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 4px; text-transform: capitalize; } ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/global/templates/emails/welcome-email/html.pug ================================================ html(lang='en') head meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') title Account Activation email || KPI Library link(href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i', rel='stylesheet') link(rel='shortcut icon', type='image/x-icon', href='images/favicon.ico') link(rel='stylesheet', href='../assets/styles/style.css', type='text/css') body(data-gr-c-s-loaded='true', style='') .template-wrapper table.body(border='0', cellpadding='0', cellspacing='0') tbody tr td   td.container .content table.main tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td a.template-logo(href='../index.html') img(src='https://kekasrijan.herokuapp.com/static/media/kpi.88a7c7c4.png', alt='') p.lead | Hello KPI Library, br | Thanks for Signup on KPI App br | We have sent User Account Activation Link below table(border='0', cellpadding='0', cellspacing='0') tbody tr td.mt30.mb30(align='center') table(border='0', cellpadding='0', cellspacing='0') tbody tr td p.user-text | Hi, span #{user.email}, br br a.btn-primary(href= activate_url) Activate your Account p Thank you p.mb0 | If you have any problems, please contact me at a.click-link(href='#') admin@gmail.com table.help-section tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td h2.text-center.mb0 Need more help? a.support-link(href='#') We're here,ready to here table tbody tr td.wrapper table(border='0', cellpadding='0', cellspacing='0') tbody tr td p | You received this email beacuse you just signed up for new account. If it look weird a.default-link(href='#') view it in your browser .footer table(border='0', cellpadding='0', cellspacing='0') tbody tr td.content-block p.text-center | © 2018 KPI App, Goa India br | If these emails get annoying, please feel to a(href='#') unsubscribe td   ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/global/templates/emails/welcome-email/style.css ================================================ @charset "UTF-8"; /* ------------------------------------- GLOBAL RESETS ------------------------------------- */ .container { display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } img { border: none; -ms-interpolation-mode: bicubic; max-width: 100%; } body { background-color: #f6f6f6; font-family: 'Rubik', sans-serif; font-size: 15px; line-height: 28px; -webkit-font-smoothing: antialiased; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } table { border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; } table td { font-family: sans-serif; font-size: 14px; vertical-align: top; } /* ------------------------------------- BODY & CONTAINER ------------------------------------- */ .body { background-color: #f6f6f6; width: 100%; } .lead { font-size: 18px; } .mt30 { margin-top: 30px; display: block; } .mb30 { margin-bottom: 30px; display: block; } /* 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 */ .container { display: block; Margin: 0 auto !important; /* makes it centered */ max-width: 580px; padding: 10px; width: 580px; position: relative; bottom: 140px; } /* This should also be a block element, so that it will fill 100% of the .container */ .content { box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; } /* ------------------------------------- HEADER, FOOTER, MAIN ------------------------------------- */ .template-wrapper { background-color: #03A9F4; width: 100%; height: 250px; position: relative; } .click-link { color: #03A9F4; display: inline-block; margin-bottom: 20px; } .help-section { background-color: #ffdcdc; border-radius: 3px; width: 100%; text-align: center; } .mb0 { margin-bottom: 0px; } .support-link { color: #03A9F4; display: inline-block; font-size: 19px; margin-bottom: 0px; } .template-logo { display: block; margin-bottom: 40px; margin: auto; } .user-text { font-size: 18px; font-weight: 500; } .user-text span { font-weight: 600; } .text-secondary { color: #218ef4 !important } .main { background: #ffffff; border-radius: 3px; width: 100%; margin-bottom: 20px; } .wrapper { box-sizing: border-box; padding: 40px 25px; } .content-block { padding-bottom: 10px; padding-top: 10px; line-height: 2; } .footer { clear: both; text-align: center; width: 100%; } .footer td, .footer p, .footer span, .footer a { color: #999999; font-size: 12px; text-align: center; } /* ------------------------------------- TYPOGRAPHY ------------------------------------- */ h1, h2, h3, h4 { color: #000000; font-family: sans-serif; font-weight: 400; line-height: 1.4; margin: 0; Margin-bottom: 30px; } h1 { font-size: 35px; font-weight: 300; text-align: center; text-transform: capitalize; } p, ul, ol { font-family: sans-serif; font-size: 15px; font-weight: normal; margin: 0; margin-bottom: 15px; } p li, ul li, ol li { list-style-position: inside; margin-left: 5px; } a { color: #3498db; text-decoration: underline; } /* ------------------------------------- BUTTONS ------------------------------------- */ .btn { box-sizing: border-box; width: 100%; } .btn>tbody>tr>td { padding-bottom: 15px; } .btn table { width: auto; } .btn table td { background-color: #ffffff; border-radius: 5px; text-align: center; } .btn a { background-color: #ffffff; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; color: #3498db; cursor: pointer; display: inline-block; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-decoration: none; text-transform: capitalize; } .btn-primary table td { background-color: #3498db; } .btn-primary a { background-color: #3498db; border-color: #3498db; color: #ffffff; } .default-link { color: #3498db; } .default-link:hover { color: #3498db; } /* ------------------------------------- OTHER STYLES THAT MIGHT BE USEFUL ------------------------------------- */ .last { margin-bottom: 0; } .first { margin-top: 0; } .align-center { text-align: center; } .align-right { text-align: right; } .align-left { text-align: left; } .clear { clear: both; } .mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; } .preheader { color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; visibility: hidden; width: 0; } .powered-by a { text-decoration: none; } hr { border: 0; border-bottom: 1px solid #f6f6f6; Margin: 20px 0; } /* ------------------------------------- RESPONSIVE AND MOBILE FRIENDLY STYLES ------------------------------------- */ @media only screen and (max-width: 620px) { table[class=body] h1 { font-size: 28px !important; margin-bottom: 10px !important; } table[class=body] p, table[class=body] ul, table[class=body] ol, table[class=body] td, table[class=body] span, table[class=body] a { font-size: 16px !important; } table[class=body] .wrapper, table[class=body] .article { padding: 10px !important; } table[class=body] .content { padding: 0 !important; } table[class=body] .container { padding: 0 !important; width: 100% !important; } table[class=body] .main { border-left-width: 0 !important; border-radius: 0 !important; border-right-width: 0 !important; } table[class=body] .btn table { width: 100% !important; } table[class=body] .btn a { width: 100% !important; } table[class=body] .img-responsive { height: auto !important; max-width: 100% !important; width: auto !important; } } /* ------------------------------------- PRESERVE THESE STYLES IN THE HEAD ------------------------------------- */ @media all { .ExternalClass { width: 100%; } .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; } .apple-link a { color: inherit !important; font-family: inherit !important; font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; text-decoration: none !important; } .btn-primary table td:hover { background-color: #34495e !important; } .btn-primary a:hover { background-color: #03A9F4 !important; border-color: #03A9F4 !important; } } .btn-primary { text-decoration: none; color: #FFF; background-color: #03A9F4; border: solid #03A9F4; border-width: 6px 18px; line-height: 2em; /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ /*line-height: 28px;*/ font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 4px; text-transform: capitalize; } ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/global/templates/response/index.ts ================================================ class ResponseTemplate { static general(data) { return data; } static error(code, message, description) { return { statusCode: code || 400, message: message || 'some error occoured', description: description || 'error occoured on server, please try again after some time.' }; } static authError() { return this.error( 403, 'authentication error', 'no authentication token provided, please login first and provide the authentication token.' ); } static invalidAuthError() { return this.error( 403, 'authentication error', 'invalid Token provided, please login first and provide the authentication token.' ); } static emptyContent() { return this.general({ statusCode: 402, message: 'empty content found', description: 'you must provide valid data and it must not be empty.', helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json'] }); } static invalidContentType() { return this.general({ statusCode: 400, message: 'invalid content type', description: 'you must specify content type and it must be application/json', helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type'] }); } static routeNotFound() { return this.error( 405, 'resource not found', 'the resource your tried to access doesn\'t exist or you dont have permissions to access it.' ); } static userNotFound() { return this.error( 400, 'user not found', "the user you're looking for doesn't exist or you dont have permissions to access it." ); } static updateErrorOccoured(error) { return this.error( 301, 'error occoured', error || 'error occoured while updating your data.' ); } static success(description, data=null) { return { statusCode: 200, message: 'success', description: description || 'data successfully saved.', ...data } } } export default ResponseTemplate; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/helper/bcrypt.ts ================================================ const bcrypt = require('bcrypt-nodejs'); const jwt = require('jsonwebtoken'); const {url} = global['configuration'] const {uploadpath} = global['configuration'] const path = require('path'); const fs = require('fs'); const helper = { generateSaltValue(password) { const salt = bcrypt.genSaltSync(); // enter number of rounds, default: 10 const hash = bcrypt.hashSync(password, salt); return hash; }, comparePassword(userPassword, password ) { if (!userPassword.length || !( password && password.length > 0) ) { return false; } return bcrypt.compareSync(userPassword, password); }, authRedirectUrl( path ) { return `${url.FE}/#/auth/validate-token/${path}`; }, buildUserToken(data) { return { email: data.email, id:data._id, username: data.username ? data.username : data.email, hasPassword: data.password ? true : false, type : data.type || 1, picture : data.picture } }, resource( path ) { return `${url.API}${path}`; }, getFileExtension( file ) { let extensions = file.split('.'); if ( extensions.length === 1 ) { return 'jpg'; } else { return extensions.pop(); } }, avatarURL( filename ) { if ( filename.includes('://') ) { return filename; } return this.resource(`/${uploadpath.uploaddir}/${uploadpath.profiledir}/${filename}`); }, userDocumentURL( filename ) { if ( filename.includes('://') ) { return filename; } return this.resource(`/${uploadpath.uploaddir}/${uploadpath.documentdir}/${filename}`); }, randomString() { return Math.random().toString(36).substring(2, 7); }, deleteFile( type, filename ) { let location; if ( type === 'profile' ) { location = path.join( uploadpath.uploaddir, uploadpath.profiledir ) } else { location = uploadpath.uploaddir; } if (filename) { fs.unlink( path.join( location, filename ), () => { // in case we need to perform additional operations. }); } }, getPaymentMethodName( method ) { if ( method == 1 ) { return 'PayPal'; } else if ( method == 2 ) { return 'PayPal'; } else if ( method == 3 ) { return 'Instamojo'; } else { return 'Not Specified'; } }, getCurrency(currency) { let allCurrency = { 1: 'USD', 2: 'INR', }; if( allCurrency[currency] ) { return allCurrency[currency]; } else { return allCurrency[1]; } }, verificationCode() { let code = Math.floor((Math.random()*999999)+111111); return code; } }; export default helper; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/helper/email.ts ================================================ const path = require('path'); declare function require(name:string); const nodemailer = require('nodemailer'); const url = global['configuration'].url; const mailConfig = global['configuration'].email; import emailConfig from '../config/email'; import { EmailTemplate } from 'email-templates'; // const Twillo = require('./twillo'); const transport = nodemailer.createTransport({ host: 'smtp.gmail.com', port: 465, secure: true, auth: { // type: 'OAuth2', user: mailConfig.auth.user, pass: mailConfig.auth.pass }, }); const Email = { welcome(user) { if (user.email) { let templateDir = path.join('app/global/templates', 'emails', 'welcome-email'); let welcomeEmail = new EmailTemplate(templateDir); welcomeEmail.render({ user: user, activate_url: `${url.API}/auth/activate/${user.uuid}` }, (err, result) => { transport.sendMail( { from: emailConfig.global.from, to: user.email, subject: emailConfig.welcome.subject, html: result.html, }, (err, info) => { // some error occoured... console.log(err); } ); }); } }, password_reset(user, password) { if (user.email) { let templateDir = path.join('app/global/templates', 'emails', 'password-reset-email'); let passwordResetEmail = new EmailTemplate(templateDir); passwordResetEmail.render({ user: user, login_url: `${url.FE}/#/auth/login`, password: password }, (err, result) => { transport.sendMail( { from: emailConfig.global.from, to: user.email, subject: emailConfig.password_reset.subject, html: result.html, }, (err, info) => { // some error occoured... } ); }); } if (user.phone_verified) { // Twillo.password_reset_notification(user.phone); } }, }; export default Email; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/helper/errorHandler.ts ================================================ import * as winston from 'winston'; import ResponseTemplate from './responseTemplate'; /* eslint class-methods-use-this:0 */ const env = process.env.NODE_ENV; const onDevEnv = env === 'dev' || env === 'test' || env === 'local'; class errorHandler { public internalServerError(err, req, res, next) { winston.log('info',err); if (err.isBoom) { // Error From joi express validator const error = { message: err.output.payload.error, error: err.output.payload.message }; res.status(400).json(ResponseTemplate.BadRequestFromJoi(error)); } else { // internalServerError res.status(500).json({ success: false, message: err.message, error: (onDevEnv) ? err.stack : {} }); } } public PageNotFound(req, res, err) { res.status(404).json({ message: 'api not found' }); } } export default new errorHandler(); ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/helper/logger.ts ================================================ const winston = require('winston'); // define the custom settings for each transport (file, console) const options = { console: { level: 'info', handleExceptions: true, json: true, colorize: true, prettyPrint: true, humanReadableUnhandledException: true } }; const logger = new winston.Logger({ transports: [ // new winston.transports.File(options.file), new winston .transports .Console(options.console), ], exceptionHandlers: [ // new winston.transports.File(options.errorLog) ], exitOnError: false, // do not exit on handled exceptions }); // create a stream object with a 'write' function that will be used by `morgan` logger.stream = { write(message, encoding) { logger.info(message); } }; export default logger; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/helper/responseTemplate.ts ================================================ /* istanbul ignore file */ const data: any = { general(data) { return data; }, successMessage(message) { return { success: true, message }; }, success(data, message) { return { success: true, message, data }; }, error(message, err, code= null) { return { success: false, message: message || 'some error occurred', error: err || 'error occurred on server, please try again after some time.' }; }, emptyContent() { return this.general({ message: 'empty content found', description: 'you must provide valid data and it must not be empty.', helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json'] }); }, invalidContentType() { return this.general({ message: 'invalid content type', description: 'you must specify content type and it must be application/json', helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type'] }); }, BadRequestFromJoi(err) { return this.error( err.message, err.error ); }, userAlreadyExist(err) { return this.general({ success: false, message: 'user already registered in System', description: 'user already registered in System' }); }, userdoesNotExist(err) { return this.general({ success: false, message: err.message || 'user not registered in system', description: 'user account does not exist in system' }); }, commonAuthUserDataError() { return this.error( 'Authentication error', 'token verification failed, Please try again' ); }, tokenRequiredAuthError() { return this.error( 'Authentication error, Token is required in Header', 'token verification failed, Please try again' ); }, }; export default data; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/helper/twillo.ts ================================================ const twilioConfig = global['configuration'].twilio; // import twilio from 'twilio'; const twillo = require('twilio') const client = new twillo(twilioConfig.sid, twilioConfig.token); let TwilioHelper = { phone_verification(phone_number, code, callback) { client.sendMessage({ to: phone_number, from: twilioConfig.phone, body: `Hello from Bal Bla e-Commerce-Hub\nYour verification code is ${code}`, }, (err, message) => { callback(message); }); }, password_reset_notification(phone) { client.sendMessage({ to: phone, from: twilioConfig.phone, body: `Bla Bla\nYour password has been successfully reset.`, }, (err, message) => { // }); }, default_notification(phone, message) { console.log(client); client.sendMessage({ to: phone, from: twilioConfig.phone, body: `e-Commerce-Hub-TM\n${message}`, }, (err, message) => { // }); } } export default TwilioHelper; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/lib/logger.ts ================================================ const winston = require('winston'); const moment = require('moment'); // define the custom settings for each transport (file, console) const options = { console: { level: 'info', handleExceptions: true, json: true, colorize: true, timestamp() { return moment .utc() .format(); }, prettyPrint: true, humanReadableUnhandledException: true } }; const logger = new winston.Logger({ transports: [ // new winston.transports.File(options.file), new winston .transports .Console(options.console), ], exceptionHandlers: [ // new winston.transports.File(options.errorLog) ], exitOnError: false, // do not exit on handled exceptions }); // create a stream object with a 'write' function that will be used by `morgan` logger.stream = { write(message, encoding) { logger.info(message); } }; export default logger; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/lib/mongoose.ts ================================================ /* eslint no-undef: 0 */ /* eslint import/no-dynamic-require: 0 */ // Bring Mongoose into the app const env = process.env.NODE_ENV || 'dev'; const global1 = require(`../config/environments/${env}`); const mongoConfig = global1['db'].mongo; const mongoose = require('mongoose'); // Build the connection string let dbURI = `mongodb://${mongoConfig.host}:${mongoConfig.port}/${mongoConfig.database}`; //if(env === 'test' || env === 'dev'){ // dbURI += '?authSource=admin' //} const authOptions = { auth: { user: mongoConfig.uername, password: mongoConfig.password } }; const connect = () => { // Create the database connection mongoose.connect(dbURI, (err) => { if (err) { console.log(err.message); } else { console.log('Mongoose Connected! to Database'); } }); // CONNECTION EVENTS // When successfully connected mongoose.connection.on('connected', () => { console.log(`Mongoose default connection open to ${dbURI}`); }); // If the connection throws an error mongoose.connection.on('error', (err) => { console.log(`Mongoose default connection error: ${err}`); }); // When the connection is disconnected mongoose.connection.on('disconnected', () => { console.log('Mongoose default connection disconnected'); }); // If the Node process ends, close the Mongoose connection process.on('SIGINT', () => { mongoose.connection.close(() => { console.log('Mongoose default connection disconnected through app termination'); process.exit(0); }); }); } export default connect; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/lib/requestValidator.ts ================================================ const Joi = require('joi'); const validation = { loginUser : { body : { email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), password: Joi.string().min(8).max(50).required() } }, createUser: { body: { username: Joi.string().min(4).max(50).required(), password: Joi.string().min(8).max(50).required(), email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), verify_password: Joi.string().min(6).max(50).required() }, }, resetPassword: { body: { email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), } } }; export default validation ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/middleware/authMiddleware.ts ================================================ const jwt = require("jsonwebtoken"); import responseTemplate from '../helper/responseTemplate'; import User from '../models/user'; const validation: any = { validateToken(req, res, next) { // validatr token here is its valid here const token = req.headers.authorization; if (token) { jwt.verify(token, "secretkey", (err, data) => { if (err) { res.status(403).json(responseTemplate.commonAuthUserDataError()); } else { User.findById(data.id, (error, user) => { if(error){ res.status(403).json(responseTemplate.commonAuthUserDataError()); } user.hasPassword = user.password ? true : false; req.user = user; next(); }) } }); } else { res.status(403).json(responseTemplate.tokenRequiredAuthError()); } } }; export default validation; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/middleware/requestValidator.ts ================================================ module.exports = { validatePayload(req, res, next) { // validatr token here is its valid here const token = req.body; if ((req.method === 'POST' || req.method === 'PUT') && req.body !== null) { next(); } res.status(403).json({ message: 'payload is required for HTTP Post & Put ' }); } }; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/models/plugin/plugin.ts ================================================ const datePlugin = function timestamp(schema) { // Add the two fields to the schema schema.add({ createdAt: Date, updatedAt: Date }) // Create a pre-save hook schema.pre('save', function (next) { let now = Date.now() this.updatedAt = now // Set a value for createdAt only if it is null if (!this.createdAt) { this.createdAt = now } // Call the next function in the pre-save chain next() }) } export default datePlugin; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/models/user.ts ================================================ const mongoose = require('mongoose'); const bcrypt = require('bcrypt-nodejs'); import helper from '../helper/bcrypt'; const { Schema } = mongoose; import timestampPlugin from './plugin/plugin'; import Helper from '../../app/helper/bcrypt'; const userSchema = new Schema({ provider: { type: String }, username: { type: String }, password: { type: String }, email: { index: { unique: true }, type: String }, address: { type: String }, meta: mongoose.Schema.Types.Mixed, picture : mongoose.Schema.Types.Mixed, /* reviews : [{ type: mongoose.Schema.ObjectId, ref: 'Review' }], booking : [{ type: mongoose.Schema.ObjectId, ref: 'Booking' }], vehicles: [{ type: mongoose.Schema.ObjectId, ref: 'Vehicle' }], */ uuid: { type: String }, type: { type: String, default: 1 }, status: { type: String, default: 1 }, profile_picture: mongoose.Schema.Types.Mixed, phone: String, email_verified: Boolean, phone_verified: Boolean, social: mongoose.Schema.Types.Mixed, documents: [mongoose.Schema.Types.Mixed], gender: Number, // 1: Male, 2: Female, 3: Unspecified },{ toJSON: { virtuals: true } }); userSchema.set('toObject', { virtuals: true }); userSchema.set('toJSON', { virtuals: true }); userSchema.plugin(timestampPlugin) const User = mongoose.model('User', userSchema); export default User; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/defaultRoutes.ts ================================================ import * as express from "express"; const router = express.Router(); import { Router } from "express"; export class DefaultRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public sayHello(req, res) { res.status(200).json({ success: true, message: 'i am up and running node + mongo .. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️' }); }; init() { this.router.get("/", this.sayHello); } } // Create the HeroRouter, and export its configured Express.Router const defaultRouter = new DefaultRouter(); defaultRouter.init(); export default defaultRouter.router; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/provider/Facebook.ts ================================================ import * as passport from 'passport'; const FacebookStrategy = require('passport-facebook'); import userController from '../../controller/UserController'; /* eslint no-underscore-dangle: 0 */ passport.use(new FacebookStrategy( { clientID: global.configuration.facebook.client_id, clientSecret: global.configuration.facebook.client_secret, callbackURL: global.configuration.facebook.callback_url, profileFields: ['id', 'displayName', 'photos', 'email'], passReqToCallback: true, }, (req, accessToken, refreshToken, profile, done) => { const data = profile._json; if (!data.email) { data.email = 'ramnivas.yadav@srijan.net'; } userController.registerSocial({ provider: 'facebook', name: data.name, email: data.email, phone: '5436785432', meta: { provider: 'facebook', id: profile.id, token: accessToken, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); } )); const FacebookRoutes = { authenticate: () => passport.authenticate('facebook', { scope: ['email', 'public_profile', 'user_location'] }), callback: () => passport.authenticate('facebook', { failureRedirect: '/auth/failed' }) }; export default FacebookRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/provider/Google.ts ================================================ export {} const passport = require('passport'); const GoogleStrategy = require('passport-google-oauth20').Strategy; import userController from '../../controller/UserController'; /* eslint no-underscore-dangle: 0 */ passport.use(new GoogleStrategy( { clientID: global.configuration.google.client_id, clientSecret: global.configuration.google.client_secret, callbackURL: `${global.configuration.url.API}/auth/callback/google`, profileFields: ['id', 'displayName', 'photos', 'email'] }, (accessToken, refreshToken, profile, done) => { const data = profile._json; console.log(data); userController.registerSocial({ provider: 'google', username: data.displayName, email: data.emails[0].value, phone: '5436785432', picture : data.image.url, meta: { provider: 'google', id: data.id, token: accessToken, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); } )); const GoogleRoutes = { authenticate: () => passport.authenticate('google', { scope: ['profile', 'email'] }), callback: () => passport.authenticate('google', { failureRedirect: '/login' }), function(req, res) { // Successful authentication, redirect home. res.redirect('/'); } }; export default GoogleRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/provider/Linkedin.ts ================================================ export {} const passport = require('passport'); const LinkedInStrategy = require('passport-linkedin'); import userController from '../../controller/UserController'; /* eslint no-underscore-dangle: 0 */ passport.use(new LinkedInStrategy( { consumerKey: global.configuration.linkedin.client_id, consumerSecret: global.configuration.linkedin.client_secret, callbackURL: global.configuration.linkedin.callback_url, profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline'] }, ((token, tokenSecret, profile, done) => { console.log(profile); const data = profile._json; userController.registerSocial({ provider: 'linkedin', name: `${data.firstName} ${data.lastName}`, email: data.emailAddress, mobno: '5436785432', meta: { provider: 'linkedin', id: data.id, token, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); }) )); const LinkedinRoutes = { authenticate: () => passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }), callback: () => passport.authenticate('linkedin', { failureRedirect: '/auth/failed' }) }; export default LinkedinRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/provider/Locale.ts ================================================ /* eslint prefer-destructuring:0 */ const passportModule = require('passport'); const LocalStrategy = require('passport-local'); import userController from '../../controller/UserController'; const User = require('../../models/user'); const helper = require('../../helper/bcrypt'); passportModule.use(new LocalStrategy( { usernameField: 'email', passwordField: 'password', passReqToCallback: true, session: false }, ((req, email, password, done) => { // write code here to find user if it exists in system User.find({ email }, (err, data) => { if (err) { return done(null, null); } else if (data.length === 0) { return done(null, null); } const flag = helper.comparePassword(password, data[0].password); if (!flag) { return done(null, null); } return done(null, data); }); }) )); const localRoutes = { authenticate() { return passportModule.authenticate('local', { session: false }); }, authenticate_with_callback: () => passportModule.authenticate('local', { successRedirect: '/auth/success', failureRedirect: '/auth/failed' }), }; export default localRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/provider/Twitter.ts ================================================ const passport = require('passport'); const TwitterStrategy = require('passport-twitter').Strategy; import userController from '../../controller/UserController'; passport.use(new TwitterStrategy( { consumerKey: global.configuration.twitter.client_id, consumerSecret: global.configuration.twitter.client_secret, callbackURL: 'http://127.0.0.1:3005/auth/callback/twitter' }, (token, tokenSecret, profile, done) => { console.log('data>>>', profile); const data = profile; userController.registerSocial({ provider: 'twitter', username: data.username, email: data.email || 'raam.yaadav@gmail.com', mobno: '5436785432', meta: { provider: 'twitter', id: data.id, token, } }, (err, profileData) => { if (err) { done(err, null); } done(null, profileData); }); } )); const TwitterRoutes = { authenticate: () => passport.authenticate('twitter'), callback: () => passport.authenticate('twitter', { failureRedirect: '/auth/failed' }), function(req, res) { // Successful authentication, redirect home. res.redirect('/'); } }; export default TwitterRoutes; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/routes.ts ================================================ import * as express from "express"; import UserController from "../controller/UserController"; const jwt = require("jsonwebtoken"); // seralize user Object const url = global['configuration'].url; import LocaleRoute from "./provider/Locale"; import * as expressJoiValidator from "express-joi-validator"; import expressJoi from "../lib/requestValidator"; // import FacebookRoutes from "./provider/Facebook"; import GoogleRoutes from "./provider/Google"; // import LinkedinRoutes from "./provider/Linkedin"; import Template from "../helper/responseTemplate"; // import TwitterRoute from "./provider/Twitter"; import * as template from '../helper/responseTemplate'; const boom = require("express-boom"); import { Router, Request, Response, NextFunction } from "express"; import helper from '../helper/bcrypt'; import ValidAuthTokenMiddleware from '../middleware/authMiddleware'; export class AuthRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); this.init(); } public register(req: any, res: any) { UserController.registerDefault(req, res, (error, user) => { if (error) { res.status(400).json(Template.userAlreadyExist(error.message)); } else { res.json({ statusCode: 200, success: true, message: "user created successfully", user }); } }); } public login(req: any, res: any) { UserController.validateUser(req, res, (err, token) => { if (err) { res.status(401).json(Template.userdoesNotExist(err)); } else { res.status(200).json({ success: true, message: "success", token }); } }); } public redirectSocialUser(req, res) { jwt.sign(helper.buildUserToken(req.user), "secretkey", (tokError, token) => { if (tokError) { res.boom.badImplementation(tokError); } else { // redirect app to FE app routes with Token console.log('redirecting Now...'); res.redirect(helper.authRedirectUrl(`?token=${token}`)); /* res.json({ statusCode: 200, message: "success", token }); */ } }); } public validate(req: any, res: any) { res.json({ statusCode: 200, message: 'validated succsessfully', success: true, user : req.user }); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public resetPassword(req, res) { UserController.resetPassword(req.body.email, (error, success) => { console.log(error) if (error) { res.status(403).json({ success: false, message: error, description: 'error occoured while resetting password' }); } else { res.json({ statusCode: 200, message: 'success', description: 'if this email is registered with us, you will receive a password reset email soon.', }); } }); }; public activateUserAccount(req, res) { UserController.activateUserAccount(req.params.uuid, (error, success) => { if (error) { res.status(403).json({ success: false, message: error, description: 'error occoured while activating user' }); } else { res.redirect(url.FE); } }); } /** * Take each handler, and attach to one of the Express.Router's * endpoints. */ init() { this.router.post("/login", expressJoiValidator(expressJoi.loginUser), this.login); this.router.get("/validate", ValidAuthTokenMiddleware.validateToken, this.validate); this.router.post("/register", expressJoiValidator(expressJoi.createUser), this.register); this.router.post("/reset-password", expressJoiValidator(expressJoi.resetPassword), this.resetPassword); this.router.get("/activate/:uuid", this.activateUserAccount); /** * @api {POST} /auth/login/facebook Social Login * @apiName google * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ /* this.router.get("/login/facebook", FacebookRoutes.authenticate()); this.router.get( "/callback/facebook", FacebookRoutes.callback(), this.redirectSocialUser ); */ /** * @api {POST} /auth/login/google Social Login * @apiName google * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ this.router.get("/login/google", GoogleRoutes.authenticate()); this.router.get( "/callback/google", GoogleRoutes.callback(), this.redirectSocialUser ); /** * @api {POST} /auth/login/twitter Social Login * @apiName twitter * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ /*this.router.get("/login/twitter", TwitterRoute.authenticate("twitter")); this.router.get( "/callback/twitter", TwitterRoute.callback(), this.redirectSocialUser ); */ /** * @api {POST} /auth/login/linkedin Social Login * @apiName linkedin * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ /* this.router.get("/login/likedin", LinkedinRoutes.authenticate()); this.router.get("/login/linkedin", LinkedinRoutes.authenticate()); this.router.get( "/callback/linkedin", LinkedinRoutes.callback(), this.redirectSocialUser ); */ } } // Create the HeroRouter, and export its configured Express.Router const authRoutes = new AuthRouter(); authRoutes.init(); export default authRoutes.router; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes/userRoutes.ts ================================================ import * as express from "express"; const router = express.Router(); const passport = require("passport"); import UserController from "../controller/UserController"; const jwt = require("jsonwebtoken"); // seralize user Object import ResponseTemplate from '../global/templates/response'; import * as expressJoiValidator from "express-joi-validator"; import expressJoi from "../lib/requestValidator"; const boom = require("express-boom"); import { Router } from "express"; const path = require('path') const fs = require('fs'); const { uploadpath } = global['configuration'] const multer = require('multer'); import Helper from '../helper/bcrypt'; let profileStorage = multer.diskStorage({ destination: function (req, file, cb) { cb( null, path.join( uploadpath.uploaddir, uploadpath.profiledir ) ); }, filename: function (req, file, cb) { let extension = Helper.getFileExtension(file.originalname); cb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` ); } }) let upload = multer({ storage: profileStorage }); let documentStorage = multer.diskStorage({ destination: function (req, file, cb) { cb( null, path.join( uploadpath.uploaddir, uploadpath.documentdir ) ); }, filename: function (req, file, cb) { let extension = Helper.getFileExtension(file.originalname); cb( null, `${req.user.id}-${ Helper.randomString() }.${extension}` ); } }) let uploadDocuments = multer({ storage: documentStorage }); export class AuthRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); this.init(); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public resetPassword(req, res){ UserController.resetPassword( req.body.email, ( error, success) => { console.log(error) if ( error ) { res.status(403).json({success : false, message: error, description: 'error occoured while resetting password' }); } else { res.json({ statusCode: 200, message: 'success', description: 'if this email is registered with us, you will receive a password reset email soon.', }); } }); }; public updateUser(req, res){ UserController.updateUser(req.params.email, req.body ,( error, success) => { if ( error ) { res.status(403).json({success : false, message: error, description: 'error occoured while updating user' }); } else { res.json({ statusCode: 200, message: 'success', description: 'user updated successfully', }); } }); } public getUserByEmail(req, res){ UserController.getUserByEmail(req.params.email ,( error, user) => { if ( error ) { res.status(403).json({success : false, message: error, description: 'error occoured while updating user' }); } else { res.json({ statusCode: 200, message: 'success', data: user }); } }); } public uploadProfilepicture(req, res){ UserController.updateUser( req.user.email, { picture: req.file.filename }, ( error, user ) => { if ( error ) { res.json( ResponseTemplate.updateErrorOccoured(error) ); } else { res.json( ResponseTemplate.success( 'your profile picture has been successfully uploaded', { picture: Helper.avatarURL(user.picture) }) ); Helper.deleteFile( 'profile', req.user.picture ); } }); } // upload users profile picture. public uploadDocuments(req, res){ let documents:any = {}; req.files.map( (file) => { documents.url = file.filename; documents.originalname = file.originalname; documents.timestamp = new Date(); }); UserController.updateUser( req.user.email, { document: documents }, ( error, user ) => { if ( error ) { res.json( ResponseTemplate.updateErrorOccoured(error) ); } else { let userDocuments = []; if ( user.documents ) { user.documents.map( (doc) => { userDocuments.push( Helper.userDocumentURL(doc.url) ); }); } res.json( ResponseTemplate.success( 'host documents have been successfully uploaded', { documents: userDocuments }) ); } }); } /** * Take each handler, and attach to one of the Express.Router's * endpoints. */ init() { this.router.get("/:email", this.getUserByEmail); this.router.get("/reset-password/:email",expressJoiValidator(expressJoi.resetPassword), this.resetPassword); this.router.put("/update/:email", this.updateUser); this.router.post('/upload-profile-picture', upload.single('avatar'), this.uploadProfilepicture); this.router.post('/upload-documents', uploadDocuments.array('documents'), this.uploadDocuments); } } // Create the HeroRouter, and export its configured Express.Router const authRoutes = new AuthRouter(); authRoutes.init(); export default authRoutes.router; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/routes.ts ================================================ /* eslint func-names: ["error", "never"] */ /* eslint prefer-destructuring: 0 */ import * as express from 'express'; const expressRouter= express.Router(); import authRoutes from './routes/routes'; import userRoutes from './routes/userRoutes'; import defaultRoutes from './routes/defaultRoutes'; import validAuthTokenMiddleware from './middleware/authMiddleware'; expressRouter.use('/', defaultRoutes); expressRouter.use('/uploads/', express.static('uploads')); expressRouter.use('/auth', authRoutes); expressRouter.use('/user',validAuthTokenMiddleware.validateToken, userRoutes); export default expressRouter; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/seed/seedUsers.ts ================================================ import User from '../models/user'; const mongoose = require('mongoose'); const dbName = 'blabla'; mongoose.connect(`mongodb://localhost/${dbName}`); /* eslint quote-props:0 */ /* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */ const users = [ { 'username': 'tarun', 'email': 'tarun@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1222@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun22@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun5@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun6@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'asdfg@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tgfdsa@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarunfgds8@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'asdfcv@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'dekoo@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'hellodemo@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' },{ 'username': 'tarun1', 'email': 'gmail@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 16.5377266, 'lng': 79.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' } ]; User.collection.drop(); User.create(users, (err) => { if (err) { throw (err); } console.log(`Created ${users.length} User`); mongoose.connection.close(); }); /* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal: node ./bin/seeds.js. De esta manera se crea la base de datos */ ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/seed/seedVehicle.ts ================================================ import User from '../models/user'; const mongoose = require('mongoose'); const dbName = 'blabla'; mongoose.connect(`mongodb://localhost/${dbName}`); /* eslint quote-props:0 */ /* Aquí vamos a requerir el mongoose, en donde tengo el modelo y la base de datos que creo */ const users = [ { 'username': 'tarun', 'email': 'tarun@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1222@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun22@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun5@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun1@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun6@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun7@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' }, { 'username': 'tarun1', 'email': 'tarun8@gmail.com', 'email_verified': true, 'phone_verified': false, 'gender': null, 'address': 'goa India', 'geo': { 'lat': 15.5377266, 'lng': 73.8316141 }, 'password': '$2a$10$S7FH2SqOls7bdAwosDlo0O0fw0wNW7a8e/hF.BqrE.qC9nybWnj0.', 'documents': [], 'status': '1', 'type': '2' } ]; User.collection.drop(); User.create(users, (err) => { if (err) { throw (err); } console.log(`Created ${users.length} User`); mongoose.connection.close(); }); /* Para que se cree esta base de datos tengo que poner en terminal, en otra terminal: node ./bin/seeds.js. De esta manera se crea la base de datos */ ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/transformer/userTransformer.ts ================================================ 'use strict'; import _ from 'lodash'; // import ReviewTransformer from './ReviewTransformer'; let UserTransformer = { xx : (users) =>{ if ( Array.isArray(users) ) { let output = []; users.forEach(( user ) => { output.push( UserTransformer._transformUsers(user) ); }); return output; } else { return UserTransformer._transformUsers(users); } }, transform: (users) => { if (Array.isArray(users)) { let output = []; users.forEach((user) => { output.push(UserTransformer._transform(user)); }); return output; } else { return UserTransformer._transform(users); } }, calculateUsers: (users: any | null) => { if (Array.isArray(users)) { return { Users : users.length ? users.length : 100, vehicles : (users['vehicle'] ) ? users['vehicle'].length : 1000, cities :100 } } }, _transform: (user) => { if (!user) { return {}; } let user_status = (user.status === 1) ? 'active' : 'disabled'; return { id: user._id, username : user.username, status: user_status, name: user.name, email: user.email, password: (user.password) ? true : false, phone: user.phone || '', gender: user.gender || '', birthday: user.birthday || '', type: user.type || 1, meta: user.meta || {}, social : user.social || [], phone_verified: user.phone_verified ? true : false, email_verified: user.email_verified ? true : false, profile_picture: user.profile_picture ? null : null // will fix later }; }, transformUsers: ( users ) => { if ( Array.isArray(users) ) { let output = []; users.forEach(( user ) => { output.push( UserTransformer._transformUsers(user) ); }); return output; } else { return UserTransformer._transformUsers(users); } }, _transformUsers: ( user ) => { if ( ! user ) { return {}; } let user_status = ( user.status === '1' ) ? 'active' : 'disabled'; const obj:any = {}; return Object.assign({}, { id: user._id, username : user.username, status: user_status, name: user.name, email_verified:user.email_verified, phone_verified :user.phone_verified, reviews : user.reviews, vehciles : user.vehciles, email: user.email, date : user.createdAt, type: user.type || 1, }, obj); } } export default UserTransformer; ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/types/global.d.ts ================================================ declare namespace NodeJS { export interface Global { configuration: any } } ================================================ FILE: dockerized-containers/e-Commerce-Auth/app/types/vendor.d.ts ================================================ declare namespace NodeJS { export interface Global { configuration: any } } ================================================ FILE: dockerized-containers/e-Commerce-Auth/env.sh ================================================ # this environment vairables needs to be set in .env file in applciaiton root directory # copy this file as .env and add the appropriate values as per environment. # node & mysql export NODE_ENV="dev" export PORT="3001" export MONGO_HOST="ms_commerce_mongo" export MONGO_PORT="27017" export MONGO_USERNAME="root" export MONGO_PASSWORD="root" export MONGO_DATABASE="ecommerce" export EXPRESS_SESSION_SECRET="######################" export F_CLIENTID="###################" export F_CLIENTSECRET="###########################" export F_CALLBACK="/auth/callback/facebook" export G_CLIENTID="@@@@@@@@@@@@@-###############.apps.%%%%%%%%%%%.com" export G_CLIENTSECRET="k##########@@@@@@@@@@@@Ub" export G_CALLBACK="/auth/callback/google" export L_CLIENTID="##################" export L_CLIENTSECRET="############" export L_CALLBACK="/auth/callback/linkedin" export T_CLIENTID="##################" export T_CLIENTSECRET="######################" export T_CALLBACK="/auth/callback/twitter" export FE_URL="localhost:3000" export API_KEY='XX0xxxxx-xX0X0XxXXxXxXXXxX0x' export SMTP_HOST='smtp.mandrillapp.com' export SMTP_PORT='587' export SMTP_USER='#############.net' export SMTP_PASSWORD='##############' export SID='XX0xxxxx-xX0X0XxXXxXxXXXxX0x' export TOKEN='XX0xxxxx-xX0X0XxXXxXxXXXxX0x' export PHONE='+9716156786' export FE='http://localhost:3000' export API='http://localhost:3005' export UPLOAD_DIR='uploads' export PROFILE_PICTURE_DIR='profile' export DOCUMENT_UPLOAD_DIR='documents' ================================================ FILE: dockerized-containers/e-Commerce-Auth/express.ts ================================================ import router from './app/routes'; import * as boom from 'express-boom'; import * as expressSession from 'express-session'; import * as cookieParser from 'cookie-parser'; import * as passport from 'passport'; import * as helmet from 'helmet'; import * as cors from 'cors'; import * as path from 'path'; import * as express from 'express'; import * as logger from 'morgan'; import * as bodyParser from 'body-parser'; import errorHandlers from './app/helper/errorHandler'; // Creates and configures an ExpressJS web server. class App { // ref to Express instance public express: express.Application; //Run configuration methods on the Express instance. constructor() { this.express = express(); this.middleware(); this.routes(); } // Configure Express middleware. private middleware(): void { this.express.use(passport.initialize()); // required for passport to initlize it this.express.use(expressSession({ secret: 'bla bla' })); this.express.use(passport.session()); // initlize session this.express.use(logger('dev')); this.express.disable('x-powered-by'); this.express.disable('etag'); this.express.use(helmet()); this.express.use(boom()); this.express.use(helmet.noCache({ noEtag: true })); // set Cache-Control header this.express.use(helmet.noSniff()); // set X-Content-Type-Options header this.express.use(helmet.frameguard()); // set X-Frame-Options header this.express.use(helmet.xssFilter()); // set X-XSS-Protection header // logger logs on console this.express.use(bodyParser.urlencoded({ extended: false, limit: '5mb' })); // parse application/x-www-form-urlencoded this.express.use(bodyParser.json()); // parse application/json // enable CORS this.express.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PATCH, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, api_key, Authorization, Referer'); next(); }); // register all custom Middleware this.express.use(cors({ optionsSuccessStatus: 200 })); this.express.use(cookieParser()); // cookies-parser // manage session by cookies this.express.set('views', path.join(__dirname, 'views')); // setting views this.express.set('view engine', 'hbs'); // server side template rendering this.express.use(express.static(path.join(__dirname, 'public'))); this.express.use(logger('dev')); this.express.use(bodyParser.json()); this.express.use(bodyParser.urlencoded({ extended: false })); } // Configure API endpoints. private routes(): void { passport.serializeUser((user, done) => { done(null, user); }); passport.deserializeUser((user, done) => { done(null, user); }); /* This is just to get up and running, and to make sure what we've got is * working so far. This function will change when we start to add more * API endpoints */ this.express.use('/api/v1', router); this.express.use(errorHandlers.internalServerError); this.express.use(errorHandlers.PageNotFound); } } export default new App().express; ================================================ FILE: dockerized-containers/e-Commerce-Auth/package.json ================================================ { "name": "e-commerce-hub", "version": "0.0.0", "private": true, "scripts": { "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "startdev": ". ./env.sh && cd dist && nodemon --inspect=0.0.0.0:9201 server.js && tsc --watch", "clean": "rm -rf dist", "watch": "tsc", "copy": "cp -r uploads dist/ && cp -r app/global dist/app/", "test": ". ./env.sh && NODE_ENV=test && mocha ", "debug": ". ./env.sh && NODE_ENV=test && cd dist && nodemon server.js", "prestartdev": " npm run clean && tsc && npm run copy && npm run watch", "poststartdev": "tsc --watch", "watchserver": "tsc --watch", "dev": ". ./env.sh && ts-node server.ts", "start-tsc": ". ./env.sh && nodemon ./dist/server.js", "buildAndstart": ". ./env.sh && npm run build && npm run start" }, "dependencies": { "@types/express": "^4.11.1", "assert": "^1.4.1", "axios": "^0.18.0", "bcrypt-nodejs": "0.0.3", "bluebird": "^3.5.3", "body-parser": "^1.18.3", "cookie-parser": "^1.4.3", "cors": "^2.8.5", "dotenv": "^6.1.0", "email-templates": "^2.7.1", "express": "^4.16.4", "express-boom": "^2.0.0", "express-joi-validator": "^2.0.0", "express-session": "^1.15.6", "fast-csv": "^2.4.1", "hbs": "^4.0.1", "helmet": "^3.15.0", "joi": "^14.1.1", "jsonwebtoken": "^8.4.0", "mocha": "^5.2.0", "moment": "^2.22.2", "mongoose": "^4.5.9", "morgan": "^1.9.0", "multer": "^1.2.0", "nodemailer": "2.5.0", "nodemon": "^1.18.6", "passport": "0.3.2", "passport-facebook": "2.1.1", "passport-google-oauth": "1.0.0", "passport-google-oauth20": "^1.0.0", "passport-instagram": "1.0.0", "passport-linkedin": "^1.0.0", "passport-local": "1.0.0", "passport-twitter": "1.0.4", "pug": "2.0.0-beta6", "serve-favicon": "^2.5.0", "ts-lint": "^4.5.1", "ts-node": "^7.0.1", "twilio": "^2.11.1", "typescript": "^3.1.6", "uuid": "^3.3.2", "winston": "^2.4.2" }, "devDependencies": { "@types/async": "^2.0.45", "@types/bcrypt-nodejs": "^0.0.30", "@types/bluebird": "^3.5.20", "@types/body-parser": "^1.16.8", "@types/express": "^4.11.1", "@types/mongoose": "^4.7.34", "@types/morgan": "^1.7.35", "@types/node": "^9.6.39", "@types/nodemailer": "^4.3.4", "@types/passport": "^0.4.3", "babel-eslint": "^8.0.1", "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.9.0", "eslint-plugin-node": "^5.2.1" } } ================================================ FILE: dockerized-containers/e-Commerce-Auth/public/javascripts/script.js ================================================ document.addEventListener('DOMContentLoaded', () => { console.log('IronGenerator JS imported successfully!'); }, false); ================================================ FILE: dockerized-containers/e-Commerce-Auth/public/style.scss ================================================ body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; } a { color: #00B7FF; } .h1 { font-size: 40px; } ================================================ FILE: dockerized-containers/e-Commerce-Auth/server.ts ================================================ import * as http from 'http'; import * as debug from 'debug'; // After you declare "app" const env = process.env.NODE_ENV || 'dev' console.log(` using ${process.env.NODE_ENV} to run application`); global.configuration = require(`./app/config/environments/${env}`); import App from './express'; const port = (process.env.PORT); const logger = require('winston'); import mongoose from './app/lib/mongoose'; mongoose(); const server = http.createServer(App); server.listen(process.env.PORT); server.on('error', onError); server.on('listening', onListening); function onError(error: NodeJS.ErrnoException): void { if (error.syscall !== 'listen') throw error; let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port; switch(error.code) { case 'EACCES': console.error(`${bind} requires elevated privileges`); process.exit(1); break; case 'EADDRINUSE': console.error(`${bind} is already in use`); process.exit(1); break; default: throw error; } } const gracefulStopServer = function () { // Wait 10 secs for existing connection to close and then exit. setTimeout(() => { logger.info('Shutting down server'); process.exit(0); }, 1000); }; process.on('uncaughtException', (err) => { logger.error(err, 'Uncaught exception'); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { logger.error({ promise, reason }, 'unhandledRejection'); process.exit(1); }); process.on('SIGINT', gracefulStopServer); process.on('SIGTERM', gracefulStopServer); function onListening(): void { let addr = server.address(); let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`; console.log(`Listening on ${bind}`); } ================================================ FILE: dockerized-containers/e-Commerce-Auth/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "moduleResolution": "node", "pretty": true, "sourceMap": true, "target": "es6", "outDir": "./dist", "experimentalDecorators": false, "emitDecoratorMetadata": false, "skipDefaultLibCheck": false, "baseUrl": "./lib" }, "files" : [ "./app/types/vendor.d.ts" ], "include": [ "/**/*.ts" ], "exclude": [ "node_modules" ] } ================================================ FILE: dockerized-containers/e-Commerce-Auth/tslint.json ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Auth/uploads/documents/.gitkeep ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Auth/uploads/profile/.gitkeep ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Cart/.sequelizerc ================================================ const path = require('path'); module.exports = { 'config': path.resolve('config', 'config.js') } ================================================ FILE: dockerized-containers/e-Commerce-Cart/Dockerfile ================================================ FROM node:carbon # Create app directory WORKDIR /usr/src/app # Bundle app source COPY . . # npm install RUN npm install # Run npm install --global grpc --unsafe-perm EXPOSE 3004 9204 CMD [ "npm", "run", "watchserver" ] CMD [ "npm", "run", "startdev" ] ================================================ FILE: dockerized-containers/e-Commerce-Cart/README.md ================================================ # Application for e-commerce Hub REST API to support application features - Express as web framework with Typescript - Passport js for social authentication - Express CORS enabled - boom for error codes & Joi for Validation - Winston for logging and express minitor for monitoring - Mongoose as ODM driver - eslint validation extending airbnb styleguide - git hooks & CI/CD in place - Typescript based compilation tsc compiler - TDD in progress with Mocha - JWT based authentication - multiple Mongoose collection with referencing - payment gateway Integration - Heroku deployment - Mini e-commerce platform # Cart Application # "It's just simple application to provide REST APIs for mini e-commerce platform where individual can buy products and can pay the bills ``` # Application Execution ```javascript git clone repo npm install npm run startdev tsc -- watch ``` # Application configuration ```javascript env.sh need to be added locally export NODE_ENV="dev" export PORT="3005" export MONGOURL="mongodb://mongo/hello" export EXPRESS_SESSION_SECRET="************************" export F_CLIENTID="**************" export F_CLIENTSECRET="**********************" ``` # Application NPM Script ```javascript "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "clean" : "rm -rf dist", "copy" : "cp -r uploads dist/ && cp -r app/global dist/app/" ``` ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/config/environments/dev.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.db = { user: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, connectTimeout: 80000, }; configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } configuration.logLevel ='info'; module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/config/environments/qa.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.db = { user: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, connectTimeout: 80000, }; configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } configuration.logLevel ='info'; module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/config/environments/test.ts ================================================ /* eslint quote-props: 0 */ export { } const configuration: any = {}; configuration.mongo = { url: process.env.MONGODB_URI || process.env.MONGOURL, }; configuration.URL = { frontEnd: process.env.FE_URL } configuration.db = { user: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, connectTimeout: 80000, }; configuration.facebook = { client_id: process.env.F_CLIENTID, client_secret: process.env.F_CLIENTSECRET, callback_url: process.env.F_CALLBACK }; configuration.google = { client_id: process.env.G_CLIENTID, client_secret: process.env.G_CLIENTSECRET, callback_url: process.env.G_CALLBACK }; configuration.linkedin = { client_id: process.env.L_CLIENTID, client_secret: process.env.L_CLIENTSECRET, callback_url: process.env.L_CALLBACK }; configuration.twitter = { client_id: process.env.T_CLIENTID, client_secret: process.env.T_CLIENTSECRET, callback_url: process.env.T_CALLBACK }; configuration.email = { apiKey: process.env.API_KEY, host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD, } } configuration.twilio = { sid: process.env.SID, token: process.env.TOKEN, phone: process.env.PHONE, } configuration.url = { FE: process.env.FE, API: process.env.API, } configuration.uploadpath = { uploaddir: process.env.UPLOAD_DIR, profiledir: process.env.PROFILE_PICTURE_DIR } configuration.logLevel ='info'; module.exports = configuration; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/events/processEvent.ts ================================================ const events = require('events'); const eventEmitter = new events.EventEmitter(); export default eventEmitter; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/helper/errorHandler.ts ================================================ import logger from '../lib/logger'; import ResponseTemplate from './responseTemplate'; /* eslint class-methods-use-this:0 */ const env = process.env.NODE_ENV; const onDevEnv = env === 'dev' || env === 'test' || env === 'local'; class errorHandler { public internalServerError(err, req, res, next) { logger.log('info',err); if (err.isBoom) { // Error From joi express validator const error = { message: err.output.payload.error, error: err.output.payload.message }; res.status(400).json(ResponseTemplate.BadRequestFromJoi(error)); } else { // internalServerError res.status(500).json({ success: false, message: err.message, error: (onDevEnv) ? err.stack : {} }); } } public PageNotFound(req, res, err) { res.status(404).json({ message: 'api not found' }); } } export default new errorHandler(); ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/helper/errors.ts ================================================ class APIError extends Error { constructor(message, ErrorID, code = null) { super(); Error.captureStackTrace(this, this.constructor); this.name = 'api error'; this.message = message; if (ErrorID) this['ErrorID'] = ErrorID; if (code) this['code'] = code; } } export default APIError; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/helper/logger.ts ================================================ const log = require('loglevel'); log.setLevel(global.configuration.logLevel); const logger = log; export default logger; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/helper/responseTemplate.ts ================================================ /* istanbul ignore file */ const data: any = { general(data) { return data; }, successMessage(message) { return { success: true, message }; }, success(data, message) { return { success: true, message, data }; }, error(message, err, code= null) { return { success: false, message: message || 'some error occurred', error: err || 'error occurred on server, please try again after some time.' }; }, emptyContent() { return this.general({ message: 'empty content found', description: 'you must provide valid data and it must not be empty.', helpful_links: ['http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json'] }); }, invalidContentType() { return this.general({ message: 'invalid content type', description: 'you must specify content type and it must be application/json', helpful_links: ['http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type'] }); }, BadRequestFromJoi(err) { return this.error( err.message, err.error ); }, userAlreadyExist(err) { return this.general({ success: false, message: 'user already registered in System', description: 'user already registered in System' }); }, userdoesNotExist(err) { return this.general({ success: false, message: err.message || 'user not registered in system', description: 'user account does not exist in system' }); }, commonAuthUserDataError() { return this.error( 'Authentication error', 'token verification failed, Please try again' ); }, tokenRequiredAuthError() { return this.error( 'Authentication error, Token is required in Header', 'token verification failed, Please try again' ); }, }; export default data; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/lib/logger.ts ================================================ const log = require('loglevel'); log.setLevel(global.configuration.logLevel); const logger = log; export default logger; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/lib/mysql.ts ================================================ import APIError from '../helper/errors'; import logger from './logger'; const mysql = require('mysql2'); import eventEmitter from '../events/processEvent'; /* eslint func-names: ["error", "never"] */ const config = global['configuration'].db; console.log(config); let connection:any = null; try { connection = mysql.createConnection(config); } catch (err) { logger.error('Cannot establish a connection with the database'); /** To Prevent sensitive info leak, not raising actual error */ throw new APIError('Mysql connection failed (config)', 1); } connection.connect((err) => { // in case of error if (err) throw new APIError('Mysql connection failed (connect)', 1); else { logger.info(`MysqlClient connected to port ${config.port || 3306} and ${config.host} host`); eventEmitter.emit('dbReady', connection); } }); connection.on('error', (err) => { logger.error('Cannot establish a connection with the database'); /** To Prevent sensitive info leak, not raising actual error */ throw new APIError('Mysql connection failed (event)', 1); }); export default connection; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/lib/requestValidator.ts ================================================ const Joi = require('joi'); const validation = { loginUser : { body : { email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), password: Joi.string().min(8).max(50).required() } }, createUser: { body: { username: Joi.string().min(4).max(50).required(), password: Joi.string().min(8).max(50).required(), email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), verify_password: Joi.string().min(6).max(50).required() }, }, resetPassword: { body: { email: Joi.string().regex(/^[\w.]+@[\w]+?(\.[a-zA-Z]{2,3}){1,3}$/).required(), } } }; export default validation ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/middleware/requestValidator.ts ================================================ module.exports = { validatePayload(req, res, next) { // validatr token here is its valid here const token = req.body; if ((req.method === 'POST' || req.method === 'PUT') && req.body !== null) { next(); } res.status(403).json({ message: 'payload is required for HTTP Post & Put ' }); } }; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/models/data/cart.ts ================================================ const Product= { products: [ { availableSizes: [ "S", "XS" ], currencyFormat: "$", currencyId: "USD", description: "4 MSL", id: 12, installments: 9, isFreeShipping: true, price: 10.9, sku: 12064273040195392, style: "Black with custom print", title: "Cat Tee Black T-Shirt" }, { availableSizes: [ "M" ], currencyFormat: "$", currencyId: "USD", description: "", id: 13, installments: 5, isFreeShipping: true, price: 29.45, sku: 51498472915966370, style: "Front print and paisley print", title: "Dark Thug Blue-Navy T-Shirt" }, { availableSizes: [ "X", "L", "XL" ], currencyFormat: "$", currencyId: "USD", description: "GPX Poly 1", id: 14, installments: 3, isFreeShipping: true, price: 9, sku: 10686354557628304, style: "Front tie dye print", title: "Sphynx Tie Dye Wine T-Shirt" }, { availableSizes: [ "X", "L", "XL", "XXL" ], currencyFormat: "$", currencyId: "USD", description: "Treino 2014", id: 15, installments: 5, isFreeShipping: true, price: 14, sku: 11033926921508488, style: "Black T-Shirt with front print", title: "Skuul" }, { availableSizes: [ "X", "L" ], currencyFormat: "$", currencyId: "USD", description: "", id: 11, installments: 3, isFreeShipping: true, price: 13.25, sku: 39876704341265610, style: "Wine", title: "Wine Skul T-Shirt" }, { availableSizes: [ "X", "L", "XL", "XXL" ], currencyFormat: "$", currencyId: "USD", description: "14/15 s/nº", id: 0, installments: 9, isFreeShipping: true, price: 10.9, sku: 8552515751438644, style: "Branco com listras pretas", title: "Cat Tee Black T-Shirt" }, { availableSizes: [ "X", "L", "XL", "XXL" ], currencyFormat: "$", currencyId: "USD", description: "14/15 s/nº", id: 1, installments: 9, isFreeShipping: true, price: 10.9, sku: 18644119330491310, style: "Preta com listras brancas", title: "Sphynx Tie Dye Grey T-Shirt" }, { availableSizes: [ "X", "L" ], currencyFormat: "$", currencyId: "USD", description: "14/15 s/nº", id: 2, installments: 7, isFreeShipping: true, price: 14.9, sku: 11854078013954528, style: "Branco com listras pretas", title: "Danger Knife Grey" }, { availableSizes: [ "X", "L" ], currencyFormat: "$", currencyId: "USD", description: "2014 s/nº", id: 3, installments: 7, isFreeShipping: true, price: 14.9, sku: 876661122392077, style: "Preto com listras brancas", title: "White DGK Script Tee" }, { availableSizes: [ "XL" ], currencyFormat: "$", currencyId: "USD", description: "14/15 s/nº - Jogador", id: 4, installments: 12, isFreeShipping: false, price: 25.9, sku: 9197907543445676, style: "Branco com listras pretas", title: "Born On The Streets" }, { availableSizes: [ "X", "L", "XL" ], currencyFormat: "$", currencyId: "USD", description: "14/15 + Camiseta 1º Mundial", id: 5, installments: 9, isFreeShipping: false, price: 10.9, sku: 10547961582846888, style: "Preto", title: "Tso 3D Short Sleeve T-Shirt A" }, { availableSizes: [ "XL", "XXL" ], currencyFormat: "$", currencyId: "USD", description: "Goleiro 13/14", id: 6, installments: 0, isFreeShipping: true, price: 49.9, sku: 6090484789343891, style: "Branco", title: "Man Tie Dye Cinza Grey T-Shirt" }, { availableSizes: [ "S" ], currencyFormat: "$", currencyId: "USD", description: "1977 Infantil", id: 7, installments: 4, isFreeShipping: true, price: 22.5, sku: 18532669286405344, style: "Preto com listras brancas", title: "Crazy Monkey Black T-Shirt" }, { availableSizes: [ "XL" ], currencyFormat: "$", currencyId: "USD", description: "", id: 8, installments: 4, isFreeShipping: false, price: 18.7, sku: 5619496040738316, style: "Azul escuro", title: "Tso 3D Black T-Shirt" }, { availableSizes: [ "L", "XL" ], currencyFormat: "$", currencyId: "USD", description: "", id: 9, installments: 5, isFreeShipping: true, price: 134.9, sku: 11600983276356164, style: "", title: "Crazy Monkey Grey" }, { availableSizes: [ "L", "XL" ], currencyFormat: "$", currencyId: "USD", description: "", id: 10, installments: 9, isFreeShipping: true, price: 49, sku: 27250082398145996, style: "", title: "On The Streets Black T-Shirt" } ] }; export default Product; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/routes/defaultRoutes.ts ================================================ import * as express from "express"; const router = express.Router(); import { Router } from "express"; import product from '../models/data/cart'; export class DefaultRouter { router: Router; /** * Initialize the HeroRouter */ constructor() { this.router = Router(); } /** * @api {POST} /auth/reset-password update password sent in Mail * @apiName resetPassword * @apiGroup Auth * @apiSuccess {String} code HTTP status code from API. * @apiSuccess {String} message Message from API. */ public sayHello(req, res) { res.status(200).json({ success: true, message: 'i am up and running with mysql + node .. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️' }); }; public getProducts(req, res) { res.status(200).json(product); }; init() { this.router.get("/", this.sayHello); this.router.get("/products", this.getProducts); } } // Create the HeroRouter, and export its configured Express.Router const defaultRouter = new DefaultRouter(); defaultRouter.init(); export default defaultRouter.router; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/routes.ts ================================================ /* eslint func-names: ["error", "never"] */ /* eslint prefer-destructuring: 0 */ import * as express from 'express'; const expressRouter= express.Router(); import defaultRoutes from './routes/defaultRoutes'; expressRouter.use('/', defaultRoutes); export default expressRouter; ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/types/global.d.ts ================================================ declare namespace NodeJS { export interface Global { configuration: any } } ================================================ FILE: dockerized-containers/e-Commerce-Cart/app/types/vendor.d.ts ================================================ declare namespace NodeJS { export interface Global { configuration: any } } ================================================ FILE: dockerized-containers/e-Commerce-Cart/config/config.js ================================================ const fs = require('fs'); module.exports = { local: { username: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, dialect: 'mysql' }, dev: { username: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, dialect: 'mysql' }, test: { username: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, dialect: 'mysql' }, qa: { username: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, dialect: 'mysql' }, uat: { username: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, dialect: 'mysql' }, prod: { username: process.env.USERNAME, password: process.env.PASSWORD, database: process.env.DATABASE, host: process.env.HOST, dialect: 'mysql' } }; ================================================ FILE: dockerized-containers/e-Commerce-Cart/env.sh ================================================ # this environment vairables needs to be set in .env file in applciaiton root directory # copy this file as .env and add the appropriate values as per environment. # node & mysql export NODE_ENV="dev" export PORT="3004" export USERNAME="root" export PASSWORD="root" export DATABASE="cartDB" export HOST="mysql" ================================================ FILE: dockerized-containers/e-Commerce-Cart/express.ts ================================================ import router from './app/routes'; import * as boom from 'express-boom'; import * as expressSession from 'express-session'; import * as cookieParser from 'cookie-parser'; import * as passport from 'passport'; import * as helmet from 'helmet'; import * as cors from 'cors'; import * as path from 'path'; import * as express from 'express'; import * as logger from 'morgan'; import * as bodyParser from 'body-parser'; import errorHandlers from './app/helper/errorHandler'; // Creates and configures an ExpressJS web server. class App { // ref to Express instance public express: express.Application; //Run configuration methods on the Express instance. constructor() { this.express = express(); this.middleware(); this.routes(); } // Configure Express middleware. private middleware(): void { this.express.use(passport.initialize()); // required for passport to initlize it this.express.use(expressSession({ secret: 'bla bla' })); this.express.use(passport.session()); // initlize session this.express.use(logger('dev')); this.express.disable('x-powered-by'); this.express.disable('etag'); this.express.use(helmet()); this.express.use(boom()); this.express.use(helmet.noCache({ noEtag: true })); // set Cache-Control header this.express.use(helmet.noSniff()); // set X-Content-Type-Options header this.express.use(helmet.frameguard()); // set X-Frame-Options header this.express.use(helmet.xssFilter()); // set X-XSS-Protection header // logger logs on console this.express.use(bodyParser.urlencoded({ extended: false, limit: '5mb' })); // parse application/x-www-form-urlencoded this.express.use(bodyParser.json()); // parse application/json // enable CORS this.express.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PATCH, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, api_key, Authorization, Referer'); next(); }); // register all custom Middleware this.express.use(cors({ optionsSuccessStatus: 200 })); this.express.use(cookieParser()); // cookies-parser // manage session by cookies this.express.set('views', path.join(__dirname, 'views')); // setting views this.express.set('view engine', 'hbs'); // server side template rendering this.express.use(express.static(path.join(__dirname, 'public'))); this.express.use(logger('dev')); this.express.use(bodyParser.json()); this.express.use(bodyParser.urlencoded({ extended: false })); } // Configure API endpoints. private routes(): void { passport.serializeUser((user, done) => { done(null, user); }); passport.deserializeUser((user, done) => { done(null, user); }); /* This is just to get up and running, and to make sure what we've got is * working so far. This function will change when we start to add more * API endpoints */ this.express.use('/api/v1', router); this.express.use(errorHandlers.internalServerError); this.express.use(errorHandlers.PageNotFound); } } export default new App().express; ================================================ FILE: dockerized-containers/e-Commerce-Cart/mysql/schema.sql ================================================ CREATE DATABASE IF NOT EXISTS `shopping_cart_db` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `shopping_cart_db`; DROP TABLE IF EXISTS `carts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `carts` ( `idcarts` bigint(20) NOT NULL, `idcustomer` bigint(20) NOT NULL, `subtotal` decimal(10,2) NOT NULL, PRIMARY KEY (`idcarts`), KEY `carts_customers_fk_idx` (`idcustomer`), CONSTRAINT `carts_customers_fk` FOREIGN KEY (`idcustomer`) REFERENCES `customers` (`idcustomer`) ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `categories` -- DROP TABLE IF EXISTS `categories`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `categories` ( `idcategory` int(11) NOT NULL AUTO_INCREMENT, `description` varchar(20) NOT NULL, PRIMARY KEY (`idcategory`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 PACK_KEYS=0; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `customers` -- DROP TABLE IF EXISTS `customers`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `customers` ( `idcustomer` bigint(20) NOT NULL AUTO_INCREMENT, `first_name` varchar(50) NOT NULL, `last_name` varchar(50) NOT NULL, `username` varchar(50) NOT NULL, `password` varchar(256) NOT NULL, PRIMARY KEY (`idcustomer`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `lines_item` -- DROP TABLE IF EXISTS `lines_item`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lines_item` ( `idlines_item` bigint(20) NOT NULL AUTO_INCREMENT, `idorder` bigint(20) DEFAULT NULL, `idproduct` bigint(20) NOT NULL, `quantity` int(11) NOT NULL, `price` decimal(10,2) NOT NULL, `idcart` bigint(20) NOT NULL, PRIMARY KEY (`idlines_item`), KEY `lines_item_orders_fk_idx` (`idorder`), KEY `lines_item_products_fk_idx` (`idproduct`), KEY `lines_item_carts_fk_idx` (`idcart`), CONSTRAINT `lines_item_orders_fk` FOREIGN KEY (`idorder`) REFERENCES `orders` (`idcustomer`) ON UPDATE CASCADE, CONSTRAINT `lines_item_carts_fk` FOREIGN KEY (`idcart`) REFERENCES `carts` (`idcarts`) ON UPDATE CASCADE, CONSTRAINT `lines_item_products_fk` FOREIGN KEY (`idproduct`) REFERENCES `products` (`idproduct`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `orders` -- DROP TABLE IF EXISTS `orders`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `orders` ( `idorder` bigint(20) NOT NULL AUTO_INCREMENT, `ordered` datetime NOT NULL, `status` varchar(20) NOT NULL, `idcustomer` bigint(20) NOT NULL, `total` decimal(10,2) NOT NULL, PRIMARY KEY (`idorder`), KEY `orders_customers_fk_idx` (`idcustomer`), CONSTRAINT `orders_customers_fk` FOREIGN KEY (`idcustomer`) REFERENCES `customers` (`idcustomer`) ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `products` -- DROP TABLE IF EXISTS `products`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `products` ( `idproduct` bigint(20) NOT NULL AUTO_INCREMENT, `description` varchar(100) NOT NULL, `price` decimal(10,2) NOT NULL, `idcategory` int(11) DEFAULT NULL, PRIMARY KEY (`idproduct`), KEY `products_categories_fk` (`idcategory`), CONSTRAINT `products_categories_fk` FOREIGN KEY (`idcategory`) REFERENCES `categories` (`idcategory`) ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; ================================================ FILE: dockerized-containers/e-Commerce-Cart/package.json ================================================ { "name": "e-commerce-hub", "version": "0.0.0", "private": true, "scripts": { "start:local": " . ./env.sh && NODE_ENV=local nodemon app/server.js ", "create:local": ". ./env.sh && NODE_ENV=local ./node_modules/.bin/sequelize db:create", "migrate:local": ". ./env.sh && NODE_ENV=local ./node_modules/.bin/sequelize db:migrate", "seed:local": " . ./env.sh && NODE_ENV=local ./node_modules/.bin/sequelize db:migrate --migrations-path seeders", "start": "cd dist && nodemon server.js", "prestart": "tsc && cp -r uploads dist/ && cp -r app/global dist/app/", "startdev": ". ./env.sh && cd dist && nodemon server.js", "clean": "rm -rf dist", "watch": "tsc", "copy": "cp -r uploads dist/ && cp -r app/global dist/app/", "test": ". ./env.sh && NODE_ENV=test && mocha ", "debug": ". ./env.sh && NODE_ENV=test && cd dist && nodemon --inspect=0.0.0.0:9230 server.js", "prestartdev": " npm run clean && tsc && npm run copy && npm run watch", "poststartdev": "tsc --watch", "watchserver": "tsc --watch", "dev": ". ./env.sh && ts-node server.ts", "start-tsc": ". ./env.sh && nodemon ./dist/server.js", "buildAndstart": ". ./env.sh && npm run build && npm run start" }, "dependencies": { "@types/express": "^4.11.1", "assert": "^1.4.1", "axios": "^0.18.0", "bcrypt-nodejs": "0.0.3", "bluebird": "^3.5.3", "body-parser": "^1.18.3", "cookie-parser": "^1.4.3", "cors": "^2.8.5", "dotenv": "^6.1.0", "email-templates": "^2.7.1", "express": "^4.16.4", "express-boom": "^2.0.0", "express-joi-validator": "^2.0.0", "express-session": "^1.15.6", "fast-csv": "^2.4.1", "hbs": "^4.0.1", "helmet": "^3.15.0", "joi": "^14.1.1", "jsonwebtoken": "^8.4.0", "loglevel": "^1.6.1", "mocha": "^5.2.0", "moment": "^2.22.2", "mongoose": "^4.5.9", "morgan": "^1.9.0", "multer": "^1.2.0", "mysql2": "^1.6.5", "nodemailer": "2.5.0", "nodemon": "^1.18.6", "passport": "0.3.2", "passport-facebook": "2.1.1", "passport-google-oauth": "1.0.0", "passport-google-oauth20": "^1.0.0", "passport-instagram": "1.0.0", "passport-linkedin": "^1.0.0", "passport-local": "1.0.0", "passport-twitter": "1.0.4", "pug": "2.0.0-beta6", "sequelize": "^4.37.4", "sequelize-cli": "^4.0.0", "serve-favicon": "^2.5.0", "ts-lint": "^4.5.1", "ts-node": "^7.0.1", "twilio": "^2.11.1", "typescript": "^3.1.6", "uuid": "^3.3.2" }, "devDependencies": { "@types/async": "^2.0.45", "@types/bcrypt-nodejs": "^0.0.30", "@types/bluebird": "^3.5.20", "@types/body-parser": "^1.16.8", "@types/express": "^4.11.1", "@types/mongoose": "^4.7.34", "@types/morgan": "^1.7.35", "@types/node": "^9.6.39", "@types/nodemailer": "^4.3.4", "@types/passport": "^0.4.3", "babel-eslint": "^8.0.1", "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.9.0", "eslint-plugin-node": "^5.2.1" } } ================================================ FILE: dockerized-containers/e-Commerce-Cart/public/javascripts/script.js ================================================ document.addEventListener('DOMContentLoaded', () => { console.log('IronGenerator JS imported successfully!'); }, false); ================================================ FILE: dockerized-containers/e-Commerce-Cart/public/style.scss ================================================ body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; } a { color: #00B7FF; } .h1 { font-size: 40px; } ================================================ FILE: dockerized-containers/e-Commerce-Cart/server.ts ================================================ import * as http from 'http'; import * as debug from 'debug'; // After you declare "app" const env = process.env.NODE_ENV || 'dev' console.log(` using ${process.env.NODE_ENV} to run application`); global.configuration = require(`./app/config/environments/${env}`); import App from './express'; import eventEmitter from './app/events/processEvent' const port = (process.env.PORT); import logger from './app/lib/logger'; import mysql from './app/lib/mysql'; global['connection'] = mysql const appServer = http.createServer(App); appServer.on('error', onError); appServer.on('listening', onListening); if (!module.parent) { eventEmitter.on('dbReady', (connection) => { const port = process.env.PORT; appServer.listen(process.env.PORT, () => { logger.info(`API running in environment ${process.env.NODE_ENV}`); logger.info(`API running at http://localhost:${port}`); }, ); appServer.setTimeout(200000); if (process['parent']) process.send('ready'); }); } function onError(error: NodeJS.ErrnoException): void { if (error.syscall !== 'listen') throw error; let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port; switch(error.code) { case 'EACCES': console.error(`${bind} requires elevated privileges`); process.exit(1); break; case 'EADDRINUSE': console.error(`${bind} is already in use`); process.exit(1); break; default: throw error; } } const gracefulStopServer = function () { // Wait 10 secs for existing connection to close and then exit. setTimeout(() => { logger.info('Shutting down server'); process.exit(0); }, 1000); }; process.on('uncaughtException', (err) => { logger.error(err, 'Uncaught exception'); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { logger.error({ promise, reason }, 'unhandledRejection'); process.exit(1); }); process.on('SIGINT', gracefulStopServer); process.on('SIGTERM', gracefulStopServer); function onListening(): void { let addr = appServer.address(); let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`; debug(`Listening on ${bind}`); } ================================================ FILE: dockerized-containers/e-Commerce-Cart/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "moduleResolution": "node", "pretty": true, "sourceMap": true, "target": "es6", "outDir": "./dist", "experimentalDecorators": false, "emitDecoratorMetadata": false, "skipDefaultLibCheck": false, "baseUrl": "./lib" }, "files" : [ "./app/types/vendor.d.ts" ], "include": [ "/**/*.ts" ], "exclude": [ "node_modules" ] } ================================================ FILE: dockerized-containers/e-Commerce-Cart/tslint.json ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Cart/uploads/documents/.gitkeep ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Cart/uploads/profile/.gitkeep ================================================ ================================================ FILE: dockerized-containers/e-Commerce-Client/Dockerfile ================================================ FROM node:carbon # Create app directory WORKDIR /usr/src/app # Bundle app source COPY . . # npm install RUN npm install # Run npm install --global grpc --unsafe-perm EXPOSE 3003 CMD [ "npm", "run", "start" ] ================================================ FILE: dockerized-containers/e-Commerce-Client/README.md ================================================ ## Simple ecommerce cart application ## Basic Overview - This simple shopping cart prototype shows how React components and Redux can be used to build a friendly user experience with instant visual updates and scaleable code in ecommerce applications. #### Features - Add and remove products from the floating cart - Sort products by highest to lowest and lowest to highest price - Filter products by available sizes - Products persist in floating cart even after page reloads - Responsive design for desktop, tablets and mobile - Product stoppers for free shipping - Unit tests, integration tests and e2e testing #### Using - React - Redux - state management - Nodejs - Express CORS Middleware (Node and React run in different port) - Nodemon - for a better development experience - Concurrently - To run multiple tasks at once - Axios - for promise HTTP requests - CSS - BEM methodology - SASS - Moxios - to stub http request - Enzyme - to mount, shallow, render and query the DOM tree of React components - Webdriverio - to do automated tests in a real browser environment - Native local storage - to persist products in cart even after page reload #### Requirements - Node.js - NPM ```javascript /* First, Install the needed packages */ npm install /* Then start both Node and React */ npm start /* To run the tests */ npm run test /* Running e2e tests */ npm run wdio ``` ## About tests - Unit tests - All components have at least a basic smoke test - Integration tests - Fetch product and add to cart properly - e2e - Webdriverio - Add and remove product from cart ================================================ FILE: dockerized-containers/e-Commerce-Client/env.sh ================================================ # this environment vairables needs to be set in .env file in applciaiton root directory # copy this file as .env and add the appropriate values as per environment. # node & mysql export NODE_ENV="local" export PORT="3003" ================================================ FILE: dockerized-containers/e-Commerce-Client/firebase.json ================================================ { "hosting": { "public": "build", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ] } } ================================================ FILE: dockerized-containers/e-Commerce-Client/package.json ================================================ { "name": "app", "version": "0.1.0", "private": true, "dependencies": { "antd": "^3.13.2", "axios": "^0.18.0", "concurrently": "^4.0.1", "cors": "^2.8.5", "express": "^4.16.4", "immutable": "^4.0.0-rc.12", "moxios": "^0.4.0", "react": "^16.6.1", "react-dom": "^16.6.1", "react-redux": "^5.1.1", "react-router": "^3.2.0", "react-router-dom": "^4.3.1", "react-scripts": "^2.1.3", "redux": "^4.0.1", "redux-thunk": "^2.3.0" }, "scripts": { "start": ". ./env.sh && react-scripts start", "wdio": "wdio", "build": "react-scripts build", "test": "react-scripts test", "test:coverage": "npm run test -- --coverage", "format": "prettier --write \"**/*.+(js|json|css)\"", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "jest": { "collectCoverageFrom": [ "src/**/*.{js,jsx}", "!/node_modules/", "!src/index.js", "!src/Root.js" ] }, "browserslist": [ ">0.2%", "not dead", "not ie <= 11", "not op_mini all" ], "devDependencies": { "chai": "^4.2.0", "enzyme": "^3.7.0", "enzyme-adapter-react-16": "^1.7.0", "enzyme-to-json": "^3.3.4", "fetch-mock": "^7.2.5", "firebase-tools": "^6.2.2", "node-sass": "^4.10.0", "nodemon": "^1.18.6", "prop-types": "^15.6.2", "react-test-renderer": "^16.6.3", "redux-mock-store": "^1.5.3", "sinon": "^7.1.1", "wdio-mocha-framework": "^0.6.4", "wdio-selenium-standalone-service": "0.0.12", "wdio-spec-reporter": "^0.1.5", "webdriverio": "^4.14.1" } } ================================================ FILE: dockerized-containers/e-Commerce-Client/public/index.html ================================================ React Shopping Cart
================================================ FILE: dockerized-containers/e-Commerce-Client/public/manifest.json ================================================ { "short_name": "React App", "name": "Create React App Sample", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" } ================================================ FILE: dockerized-containers/e-Commerce-Client/public/normalize.css ================================================ /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ /** * 1. Set default font family to sans-serif. * 2. Prevent iOS text size adjust after orientation change, without disabling * user zoom. */ html { -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /** * Remove default margin. */ body { margin: 0; } /* HTML5 display definitions ========================================================================== */ /** * Correct `block` display not defined for any HTML5 element in IE 8/9. * Correct `block` display not defined for `details` or `summary` in IE 10/11 * and Firefox. * Correct `block` display not defined for `main` in IE 11. */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } /** * 1. Correct `inline-block` display not defined in IE 8/9. * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. */ audio, canvas, progress, video { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } /** * Prevent modern browsers from displaying `audio` without controls. * Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /** * Address `[hidden]` styling not present in IE 8/9/10. * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. */ [hidden], template { display: none; } /* Links ========================================================================== */ /** * Remove the gray background color from active links in IE 10. */ a { background-color: transparent; } /** * Improve readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* Text-level semantics ========================================================================== */ /** * Address styling not present in IE 8/9/10/11, Safari, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /** * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. */ b, strong { font-weight: bold; } /** * Address styling not present in Safari and Chrome. */ dfn { font-style: italic; } /** * Address variable `h1` font-size and margin within `section` and `article` * contexts in Firefox 4+, Safari, and Chrome. */ h1 { font-size: 2em; margin: 0.67em 0; } /** * Address styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /** * Address inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* Embedded content ========================================================================== */ /** * Remove border when inside `a` element in IE 8/9/10. */ img { border: 0; } /** * Correct overflow not hidden in IE 9/10/11. */ svg:not(:root) { overflow: hidden; } /* Grouping content ========================================================================== */ /** * Address margin not present in IE 8/9 and Safari. */ figure { margin: 1em 40px; } /** * Address differences between Firefox and other browsers. */ hr { box-sizing: content-box; height: 0; } /** * Contain overflow in all browsers. */ pre { overflow: auto; } /** * Address odd `em`-unit font size rendering in all browsers. */ code, kbd, pre, samp { font-family: monospace, monospace; font-size: 1em; } /* Forms ========================================================================== */ /** * Known limitation: by default, Chrome and Safari on OS X allow very limited * styling of `select`, unless a `border` property is set. */ /** * 1. Correct color not being inherited. * Known issue: affects color of disabled elements. * 2. Correct font properties not being inherited. * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. */ button, input, optgroup, select, textarea { color: inherit; /* 1 */ font: inherit; /* 2 */ margin: 0; /* 3 */ } /** * Address `overflow` set to `hidden` in IE 8/9/10/11. */ button { overflow: visible; } /** * Address inconsistent `text-transform` inheritance for `button` and `select`. * All other form control elements do not inherit `text-transform` values. * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. * Correct `select` style inheritance in Firefox. */ button, select { text-transform: none; } /** * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` * and `video` controls. * 2. Correct inability to style clickable `input` types in iOS. * 3. Improve usability and consistency of cursor style between image-type * `input` and others. */ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /** * Re-set default cursor for disabled elements. */ button[disabled], html input[disabled] { cursor: default; } /** * Remove inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /** * Address Firefox 4+ setting `line-height` on `input` using `!important` in * the UA stylesheet. */ input { line-height: normal; } /** * It's recommended that you don't attempt to style these elements. * Firefox's implementation doesn't respect box-sizing, padding, or width. * * 1. Address box sizing set to `content-box` in IE 8/9/10. * 2. Remove excess padding in IE 8/9/10. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Fix the cursor style for Chrome's increment/decrement buttons. For certain * `font-size` values of the `input`, it causes the cursor style of the * decrement button to change from `default` to `text`. */ input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Address `appearance` set to `searchfield` in Safari and Chrome. * 2. Address `box-sizing` set to `border-box` in Safari and Chrome * (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ /* 2 */ box-sizing: content-box; } /** * Remove inner padding and search cancel button in Safari and Chrome on OS X. * Safari (but not Chrome) clips the cancel button when the search input has * padding (and `textfield` appearance). */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /** * 1. Correct `color` not being inherited in IE 8/9/10/11. * 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /** * Remove default vertical scrollbar in IE 8/9/10/11. */ textarea { overflow: auto; } /** * Don't inherit the `font-weight` (applied by a rule above). * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. */ optgroup { font-weight: bold; } /* Tables ========================================================================== */ /** * Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; } td, th { padding: 0; } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/api/index.js ================================================ import config from '../config/server'; import axios from 'axios'; export function url(resource) { if (!resource) { return `${config.url}` } console.log(`${config.url}${config[resource]}`); return `${config.url}${config[resource]}` } export function setAuthToken(token) { if (token) { axios.defaults.headers.common['authorization'] = `${token}`; } else { delete axios.defaults.headers.common['authorization']; } } export function setGeoLocation(location) { if (location) { axios.defaults.headers.common['Location'] = `${location.lng},${location.lat}`; } else { delete axios.defaults.headers.common['Location']; } } export function getAuthToken() { return localStorage.token; } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/App/index.js ================================================ import React, { Component } from 'react'; import Shelf from '../Shelf'; import Filter from '../Shelf/Filter'; import FloatCart from '../FloatCart'; class App extends Component { render() { return (
); } } export default App; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Checkbox/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; class Checkbox extends Component { static propTypes = { label: PropTypes.string.isRequired, handleCheckboxChange: PropTypes.func.isRequired }; state = { isChecked: false }; toggleCheckboxChange = () => { const { handleCheckboxChange, label } = this.props; this.setState(({ isChecked }) => ({ isChecked: !isChecked })); handleCheckboxChange(label); }; render() { const { label, classes } = this.props; const { isChecked } = this.state; return (
); } } export default Checkbox; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/FloatCart/CartProduct/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Thumb from './../../Thumb'; import { formatPrice } from '../../../services/util'; class CartProduct extends Component { static propTypes = { product: PropTypes.object.isRequired, removeProduct: PropTypes.func.isRequired }; state = { isMouseOver: false }; handleMouseOver = () => { this.setState({ isMouseOver: true }); }; handleMouseOut = () => { this.setState({ isMouseOver: false }); }; render() { const { product, removeProduct } = this.props; const classes = ['shelf-item']; if (!!this.state.isMouseOver) { classes.push('shelf-item--mouseover'); } return (
this.handleMouseOver()} onMouseOut={() => this.handleMouseOut()} onClick={() => removeProduct(product)} />

{product.title}

{`${product.availableSizes[0]} | ${product.style}`}
Quantity: {product.quantity}

{`${product.currencyFormat} ${formatPrice(product.price)}`}

); } } export default CartProduct; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/FloatCart/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { loadCart, removeProduct } from '../../services/cart/actions'; import { updateCart } from '../../services/total/actions'; import CartProduct from './CartProduct'; import { formatPrice } from '../../services/util'; import './style.scss'; class FloatCart extends Component { static propTypes = { loadCart: PropTypes.func.isRequired, updateCart: PropTypes.func.isRequired, cartProducts: PropTypes.array.isRequired, newProduct: PropTypes.object, removeProduct: PropTypes.func, productToRemove: PropTypes.object }; state = { isOpen: false }; componentWillReceiveProps(nextProps) { if (nextProps.newProduct !== this.props.newProduct) { this.addProduct(nextProps.newProduct); } if (nextProps.productToRemove !== this.props.productToRemove) { this.removeProduct(nextProps.productToRemove); } } openFloatCart = () => { this.setState({ isOpen: true }); }; closeFloatCart = () => { this.setState({ isOpen: false }); }; addProduct = product => { const { cartProducts, updateCart } = this.props; let productAlreadyInCart = false; cartProducts.forEach(cp => { if (cp.id === product.id) { cp.quantity += product.quantity; productAlreadyInCart = true; } }); if (!productAlreadyInCart) { cartProducts.push(product); } updateCart(cartProducts); this.openFloatCart(); }; removeProduct = product => { const { cartProducts, updateCart } = this.props; const index = cartProducts.findIndex(p => p.id === product.id); if (index >= 0) { cartProducts.splice(index, 1); updateCart(cartProducts); } }; proceedToCheckout = () => { const { totalPrice, productQuantity, currencyFormat, currencyId } = this.props.cartTotal; if (!productQuantity) { alert('Add some product in the cart!'); } else { alert( `Checkout - Subtotal: ${currencyFormat} ${formatPrice( totalPrice, currencyId )}` ); } }; render() { const { cartTotal, cartProducts, removeProduct } = this.props; const products = cartProducts.map(p => { return ( ); }); let classes = ['float-cart']; if (!!this.state.isOpen) { classes.push('float-cart--open'); } return (
{/* If cart open, show close (x) button */} {this.state.isOpen && (
this.closeFloatCart()} className="float-cart__close-btn" > X
)} {/* If cart is closed, show bag with quantity of product and open cart action */} {!this.state.isOpen && ( this.openFloatCart()} className="bag bag--float-cart-closed" > {cartTotal.productQuantity} )}
{cartTotal.productQuantity} Cart
{products} {!products.length && (

Add some products in the cart
:)

)}
SUBTOTAL

{`${cartTotal.currencyFormat} ${formatPrice( cartTotal.totalPrice, cartTotal.currencyId )}`}

{!!cartTotal.installments && ( {`OR UP TO ${cartTotal.installments} x ${ cartTotal.currencyFormat } ${formatPrice( cartTotal.totalPrice / cartTotal.installments, cartTotal.currencyId )}`} )}
this.proceedToCheckout()} className="buy-btn"> Checkout
); } } const mapStateToProps = state => ({ cartProducts: state.cart.products, newProduct: state.cart.productToAdd, productToRemove: state.cart.productToRemove, cartTotal: state.total.data }); export default connect( mapStateToProps, { loadCart, updateCart, removeProduct } )(FloatCart); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/FloatCart/style.scss ================================================ .float-cart { position: fixed; top: 0; right: -450px; width: 450px; height: 100%; background-color: #1b1a20; box-sizing: border-box; transition: right 0.2s; &--open { right: 0; } &__close-btn { width: 50px; height: 50px; color: #ececec; background-color: #1b1a20; text-align: center; line-height: 50px; position: absolute; top: 0; left: -50px; cursor: pointer; &:hover { background-color: #212027; } } .bag { width: 40px; height: 40px; position: relative; display: inline-block; vertical-align: middle; margin-right: 15px; background-image: url('../../static/bag-icon.png'); background-repeat: no-repeat; background-size: contain; background-position: center; &--float-cart-closed { position: absolute; background-color: #000; background-size: 50%; left: -60px; width: 60px; height: 60px; cursor: pointer; .bag__quantity { bottom: 5px; right: 10px; } } &__quantity { display: inline-block; width: 18px; height: 18px; color: #0c0b10; font-weight: bold; font-size: 0.7em; text-align: center; line-height: 18px; border-radius: 50%; background-color: #eabf00; position: absolute; bottom: -5px; right: 0px; } } &__header { color: #ececec; box-sizing: border-box; text-align: center; padding: 45px 0; .header-title { font-weight: bold; font-size: 1.2em; vertical-align: middle; } } &__shelf-container { position: relative; min-height: 280px; padding-bottom: 200px; .shelf-empty { color: #ececec; text-align: center; line-height: 40px; } .shelf-item { position: relative; box-sizing: border-box; padding: 5%; transition: background-color 0.2s, opacity 0.2s; &::before { content: ''; width: 90%; height: 2px; background-color: rgba(0, 0, 0, 0.2); position: absolute; top: 0; left: 5%; } &--mouseover { background: #0c0b10; .shelf-item__details { .title, .desc { text-decoration: line-through; opacity: 0.6; } } .shelf-item__price { text-decoration: line-through; opacity: 0.6; } } &__del { width: 16px; height: 16px; top: 15px; right: 5%; border-radius: 50%; position: absolute; background-size: auto 100%; background-image: url('../../static/sprite_delete-icon.png'); background-repeat: no-repeat; z-index: 2; cursor: pointer; &:hover { background-position-x: -17px; } } &__thumb, &__details, &__price { display: inline-block; vertical-align: middle; } &__thumb { vertical-align: middle; width: 15%; margin-right: 3%; img { width: 100%; height: auto; } } &__details { width: 57%; .title { color: #ececec; margin: 0; } .desc { color: #5b5a5e; margin: 0; } } &__price { color: #eabf00; text-align: right; width: 25%; } } } &__footer { box-sizing: border-box; padding: 5%; position: absolute; bottom: 0; width: 100%; height: 200px; z-index: 2; background-color: #1b1a20; &::before { content: ''; width: 100%; height: 20px; display: block; position: absolute; top: -20px; left: 0; background: linear-gradient(to top, rgba(0, 0, 0, 0.2), transparent); } .sub, .sub-price { color: #5b5a5e; vertical-align: middle; display: inline-block; } .sub { width: 20%; } .sub-price { width: 80%; text-align: right; &__val, &__installment { margin: 0; } &__val { color: #eabf00; font-size: 22px; } } .buy-btn { color: #ececec; text-transform: uppercase; background-color: #0c0b10; text-align: center; padding: 15px 0; margin-top: 40px; cursor: pointer; transition: background-color 0.2s; &:hover { background-color: #000; } } } } /* MAC scrollbar para desktop*/ @media screen and (min-width: 640px) { .float-cart__content::-webkit-scrollbar { -webkit-appearance: none; width: 10px; background-color: rgba(0, 0, 0, 0.2); padding: 10px; } .float-cart__content::-webkit-scrollbar-thumb { border-radius: 4px; background-color: #0c0b10; } } .float-cart__content { height: 100%; overflow-y: scroll; } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Selectbox/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; class Selectbox extends Component { static propTypes = { options: PropTypes.array.isRequired, classes: PropTypes.string, handleOnChange: PropTypes.func.isRequired }; state = { selected: '' }; createOptions = options => options.map(o => ( )); onChange = e => { this.props.handleOnChange(e.target.value); }; render() { const { classes, options } = this.props; return ( ); } } export default Selectbox; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/Filter/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { updateFilters } from '../../../services/filters/actions'; import Checkbox from '../../Checkbox'; import './style.scss'; const availableSizes = ['XS', 'S', 'M', 'ML', 'L', 'XL', 'XXL']; class Filter extends Component { static propTypes = { updateFilters: PropTypes.func.isRequired, filters: PropTypes.array }; componentDidMount() { this.selectedCheckboxes = new Set(); } toggleCheckbox = label => { if (this.selectedCheckboxes.has(label)) { this.selectedCheckboxes.delete(label); } else { this.selectedCheckboxes.add(label); } this.props.updateFilters(Array.from(this.selectedCheckboxes)); }; createCheckbox = label => ( ); createCheckboxes = () => availableSizes.map(this.createCheckbox); render() { return (

Sizes:

{this.createCheckboxes()}
); } } const mapStateToProps = state => ({ filters: state.filters.items }); export default connect( mapStateToProps, { updateFilters } )(Filter); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/Filter/style.scss ================================================ .filters { width: 15%; margin-right: 15px; .star-button-container { text-align: center; small { color: #aaa; margin-bottom: 8px; display: inline-block; } } .title { margin-top: 2px; margin-bottom: 20px; } &-available-size { display: inline-block; margin-bottom: 10px; /* Customize the label (the container) */ label { display: inline-block; position: relative; cursor: pointer; font-size: 22px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; width: 35px; height: 35px; font-size: 0.8em; margin-bottom: 8px; margin-right: 8px; border-radius: 50%; line-height: 35px; text-align: center; /* On mouse-over, add a grey background color */ &:hover input ~ .checkmark { border: 1px solid #1b1a20; } /* When the checkbox is checked, add a blue background */ & input:checked ~ .checkmark { background-color: #1b1a20; color: #ececec; } /* Show the checkmark when checked */ & input:checked ~ .checkmark:after { display: block; } input { position: absolute; opacity: 0; cursor: pointer; } /* Create a custom checkbox */ .checkmark { position: absolute; top: 0; left: 0; width: 35px; height: 35px; font-size: 0.8em; border-radius: 50%; line-height: 35px; text-align: center; color: #1b1a20; background-color: #ececec; border: 1px solid transparent; } } } } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/ProductList/Product/index.js ================================================ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import Thumb from '../../../Thumb'; import { formatPrice } from '../../../../services/util'; import { addProduct } from '../../../../services/cart/actions'; const Product = ({ product, addProduct }) => { product.quantity = 1; let formattedPrice = formatPrice(product.price, product.currencyId); let productInstallment; if (!!product.installments) { const installmentPrice = product.price / product.installments; productInstallment = (
or {product.installments} x {product.currencyFormat} {formatPrice(installmentPrice, product.currencyId)}
); } return (
addProduct(product)} data-sku={product.sku} > {product.isFreeShipping && (
Free shipping
)}

{product.title}

{product.currencyFormat} {formattedPrice.substr(0, formattedPrice.length - 3)} {formattedPrice.substr(formattedPrice.length - 3, 3)}
{productInstallment}
Add to cart
); }; Product.propTypes = { product: PropTypes.object.isRequired, addProduct: PropTypes.func.isRequired }; export default connect( null, { addProduct } )(Product); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/ProductList/index.js ================================================ import React from 'react'; import Product from './Product'; const ProductList = ({ products }) => { return products.map(p => { return ; }); }; export default ProductList; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/ShelfHeader/index.js ================================================ import React from 'react'; import PropTypes from 'prop-types'; import Sort from '../Sort'; const ShelfHeader = props => { return (
{props.productsLength} Product(s) found.
); }; ShelfHeader.propTypes = { productsLength: PropTypes.number.isRequired }; export default ShelfHeader; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/Sort/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { updateSort } from '../../../services/sort/actions'; import Selectbox from '../../Selectbox'; const sortBy = [ { value: '', label: 'Select' }, { value: 'lowestprice', label: 'Lowest to highest' }, { value: 'highestprice', label: 'Highest to lowest' } ]; class Sort extends Component { static propTypes = { updateSort: PropTypes.func.isRequired, sort: PropTypes.string.isRequired }; handleSort = value => { this.props.updateSort(value); }; render() { return (
Order by
); } } const mapStateToProps = state => ({ sort: state.sort.type }); export default connect( mapStateToProps, { updateSort } )(Sort); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/index.js ================================================ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { fetchProducts } from '../../services/shelf/actions'; import Spinner from '../Spinner'; import ShelfHeader from './ShelfHeader'; import ProductList from './ProductList'; import './style.scss'; class Shelf extends Component { static propTypes = { fetchProducts: PropTypes.func.isRequired, products: PropTypes.array.isRequired, filters: PropTypes.array, sort: PropTypes.string }; state = { isLoading: false }; componentDidMount() { this.handleFetchProducts(); } componentWillReceiveProps(nextProps) { const { filters: nextFilters, sort: nextSort } = nextProps; if (nextFilters !== this.props.filters) { this.handleFetchProducts(nextFilters, undefined); } if (nextSort !== this.props.sort) { this.handleFetchProducts(undefined, nextSort); } } handleFetchProducts = ( filters = this.props.filters, sort = this.props.sort ) => { this.setState({ isLoading: true }); this.props.fetchProducts(filters, sort, () => { this.setState({ isLoading: false }); }); }; render() { const { products } = this.props; const { isLoading } = this.state; return ( {isLoading && }
); } } const mapStateToProps = state => ({ products: state.shelf.products, filters: state.filters.items, sort: state.sort.type }); export default connect( mapStateToProps, { fetchProducts } )(Shelf); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Shelf/style.scss ================================================ .shelf-container { display: flex; flex-wrap: wrap; width: 85%; min-height: 600px; &-header { width: 100%; margin-bottom: 10px; .products-found { float: left; margin: 0; margin-top: 8px; } .sort { float: right; select { background-color: #fff; outline: none; border: 1px solid #ececec; border-radius: 2px; margin-left: 10px; width: auto; height: 35px; cursor: pointer; &:hover { border: 1px solid #5b5a5e; } } } } .shelf-item { width: 25%; position: relative; text-align: center; box-sizing: border-box; padding: 10px; margin-bottom: 30px; border: 1px solid transparent; cursor: pointer; &:hover { border: 1px solid #eee; .shelf-item__buy-btn { background-color: #eabf00; } } .shelf-stopper { position: absolute; color: #ececec; top: 10px; right: 10px; padding: 5px; font-size: 0.6em; background-color: #1b1a20; cursor: default; } &__thumb { img { width: 100%; } } &__title { position: relative; padding: 0 20px; height: 45px; &::before { content: ''; width: 20px; height: 2px; background-color: #eabf00; position: absolute; bottom: 0; left: 50%; margin-left: -10px; } } &__price { height: 60px; .val { b { font-size: 1.5em; margin-left: 5px; } } .installment { color: #9c9b9b; } } &__buy-btn { background-color: #1b1a20; color: #fff; padding: 15px 0; margin-top: 10px; cursor: pointer; // border-bottom: 2px solid #151419; transition: background-color 0.2s; } } } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Spinner/index.js ================================================ import React from 'react'; import './style.scss'; export default () => (
); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Spinner/style.scss ================================================ .spinner.lds-ring { position: fixed; top: 50%; left: 50%; margin-left: -32px; margin-top: -32px; width: 64px; height: 64px; z-index: 10; border-radius: 5px; background-color: #000; div { box-sizing: border-box; display: block; position: absolute; width: 51px; height: 51px; margin: 6px; border: 6px solid #fff; border-radius: 50%; animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; border-color: #fff transparent transparent transparent; &:nth-child(1) { animation-delay: -0.45s; } &:nth-child(2) { animation-delay: -0.3s; } &:nth-child(3) { animation-delay: -0.15s; } } @keyframes lds-ring { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/components/Thumb/index.js ================================================ import React from 'react'; import PropTypes from 'prop-types'; const Thumb = props => { return (
{props.alt}
); }; Thumb.propTypes = { alt: PropTypes.string, title: PropTypes.string, classes: PropTypes.string, src: PropTypes.string.isRequired }; export default Thumb; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/config/index.js ================================================ import server from '../config/server'; export default { // server: server social: { facebook: server.url + 'auth/login/facebook', google: server.url + 'auth/login/google', twitter: server.url + 'auth/login/twitter', instagram: server.url + 'auth/login/instagram', }, google: { api_key: '***', }, } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/config/server.js ================================================ export default { url: 'http://ms-commerce.com/api/v1/', register: 'auth/register', login: 'auth/login', validate_auth: 'auth/validate', reset_password: 'auth/reset-password', userfetch : 'user/fetch', users: 'users', user : 'user', changeRrole: 'user/change-role' } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/index.js ================================================ import React from 'react'; import {render} from 'react-dom'; import { Router, Route, hashHistory, IndexRoute } from 'react-router'; import {notLoggedIn} from './util/middleware/index'; import { Provider } from 'react-redux'; import store from './services/store'; // ------------------Login pages-------------------// import RegisterPage from './services/auth/Register'; import LoginPage from './services/auth/Login'; import LogoutPage from './services/auth/Logout'; import ResetPasswordPage from './services/auth/ResetPassword'; import ValidateTokenPage from './services/auth/ValidateToken'; import AuthLayout from './layout/Auth'; //------------------dashboard-------------------// import PublicLayout from './layout/Public'; import PublicIndexPage from './components/App'; render(( ), document.getElementById("root")); ================================================ FILE: dockerized-containers/e-Commerce-Client/src/index.scss ================================================ @import url('https://fonts.googleapis.com/css?family=Roboto'); body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } body { margin: 0; color: #1b1a20; font-family: 'Roboto', sans-serif; } main { display: flex; padding: 20px 2%; max-width: 1200px; margin: 50px auto 0 auto; } @media only screen and (max-width: 1024px) { body { .filters { width: 20%; } .shelf-container { width: 80%; .shelf-item { width: 33.33%; } } } } @media only screen and (max-width: 640px) { body { .filters { width: 25%; } .shelf-container { width: 75%; .shelf-item { width: 50%; padding: 10px; &__title { margin-top: 5px; padding: 0; } } } .float-cart { width: 100%; right: -100%; &--open { right: 0; } &__close-btn { left: 0px; z-index: 2; background-color: #1b1a20; } &__header { padding: 25px 0; } } } } @media only screen and (max-width: 460px) { body { main { display: flex; flex-wrap: wrap; padding: 2%; margin-top: 42px; } .filters { width: 100%; margin-right: 0; text-align: center; .title { margin-bottom: 15px; } } .shelf-container-header { .products-found { width: 100%; text-align: center; margin: 10px 0; } .sort { width: 100%; text-align: center; } } .shelf-container { width: 100%; .shelf-item { width: 50%; &__buy-btn { display: none; } } } } } ================================================ FILE: dockerized-containers/e-Commerce-Client/src/layout/Auth.js ================================================ import React from 'react'; let AuthLayout = (props) => { let backgroundChoices = ['bg1', 'bg4', 'bg3', 'bg4', 'bg5']; let background_image; delete localStorage.auth_background; if (!localStorage.auth_background) { background_image = backgroundChoices[Math.floor(Math.random() * backgroundChoices.length)]; localStorage.auth_background = background_image; } else { background_image = localStorage.auth_background; } return (
{props.children}
) } export default AuthLayout; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/layout/Public.js ================================================ import React, {Component} from 'react'; import axios from 'axios'; import * as API from '../api/index'; import {message} from 'antd'; import Auth from '../util/middleware/auth'; import {connect} from 'react-redux'; import * as Action from '../services/auth/action'; const mapStateToProps = (state, ownProps) => { return { user: state.auth.get('user') } } const mapDispatchToProps = (dispatch, ownProps) => { return { authUpdateUserData: (data) => dispatch(Action.authUpdateUserData(data)) } } class PublicPage extends Component { constructor(props) { super(props); let access_token = Auth.getAccessToken() if (access_token) { API.setAuthToken(access_token); axios.get(API.url('validate_auth')) .then((response) => { const user = response.data.user; if (response.data.statusCode === 200 && response.data.success === true) { Auth.setAccessToken(access_token); this.props.authUpdateUserData(response.data.user); console.log(response.data.user); this.loadUserProfile(user.email); } else { message.error('Invalid auth token, please try logging in again', 3); Auth.deleteAccessToken(); API.setAuthToken(); } }) .catch((response) => { console.log('catch error', response); }); } } render() { return (
{this.props.children}
) } } const PublicRoutePage = connect(mapStateToProps, mapDispatchToProps)(PublicPage); export default PublicRoutePage; ================================================ FILE: dockerized-containers/e-Commerce-Client/src/services/auth/Login.js ================================================ import React from 'react' import { connect } from 'react-redux' import * as Action from './action' import { Link } from 'react-router' import { Spin, Alert } from 'antd' import Util from '../../util/helper/index'; import config from '../../config/index'; const mapStateToProps = (state, ownProps) => { return { status: state.auth.get('status'), login: state.auth.get('login') } } const mapDispatchToProps = (dispatch, ownProps) => { return { authSubmitLoginForm: status => dispatch(Action.authSubmitLoginForm(status)), authInvalidateLoginForm: value => dispatch(Action.authInvalidateLoginForm(value)), authUpdateLoginFormField: data => dispatch(Action.authUpdateLoginFormField(data)), authServerLoginUser: value => dispatch(Action.authServerLoginUser(value)) } } let LoginPage = props => { let user_email = props.login.get('email') console.log(user_email + 'user email'); let user_password = props.login.get('password') let handleSubmit = event => { event.preventDefault() props.authSubmitLoginForm(true) let errorHandler = (message, description) => { setTimeout(() => { //notification.error({message: message, description: description}); props.authInvalidateLoginForm(true) props.authSubmitLoginForm(false) }, 50) } if (!user_email || !user_password) { errorHandler( 'Error Occoured!', 'Please enter your email address and password.' ) } else if (!Util.validateEmail(user_email)) { errorHandler('Invalid Email', 'Please enter a valid email address.') } else { props.authInvalidateLoginForm(false) props.authServerLoginUser({ email: user_email, password: user_password }) } } let handleInputChange = (event, field) => { let value = event.target.value props.authUpdateLoginFormField({ field, value }) } const uiLinks = (