[
  {
    "path": ".gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# others\npackage-lock.json\nyarn.lock\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# OS\n.DS_Store\n\n# Tests\n/coverage\n/.nyc_output\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# next.js build output\n.next\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n\t\"printWidth\": 80,\n\t\"tabWidth\": 2,\n\t\"useTabs\": true,\n\t\"semi\": false,\n\t\"singleQuote\": true,\n\t\"trailingComma\": \"none\",\n\t\"bracketSpacing\": true,\n\t\"jsxBracketSameLine\": false,\n\t\"fluid\": false\n}\n"
  },
  {
    "path": ".well-known/acme-challenge/3fEzNe2klZ1GLASfExbFL6LPbdmqZf2YmefYhRT-kwk",
    "content": "3fEzNe2klZ1GLASfExbFL6LPbdmqZf2YmefYhRT-kwk.G8p-XYVA4Y6MBmzrD23IQJ2p48OttBbjGc68r6pxqWo"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Chnirt\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Procfile",
    "content": "web: npm run start:prod"
  },
  {
    "path": "README.md",
    "content": "# nestjs-restful-best-practice\n"
  },
  {
    "path": "nest-cli.json",
    "content": "{\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"name\": \"nestjs-restful-best-practice\",\n\t\"version\": \"0.0.1\",\n\t\"description\": \"\",\n\t\"author\": \"\",\n\t\"license\": \"MIT\",\n\t\"scripts\": {\n\t\t\"prebuild\": \"rimraf dist\",\n\t\t\"build\": \"NODE_ENV=production nest build\",\n\t\t\"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n\t\t\"start\": \"nest start\",\n\t\t\"start:dev\": \"nest start --watch\",\n\t\t\"start:debug\": \"nest start --debug --watch\",\n\t\t\"start:prod\": \"NODE_ENV=production node dist/main\",\n\t\t\"lint\": \"tslint -p tsconfig.json -c tslint.json\",\n\t\t\"test\": \"jest\",\n\t\t\"test:watch\": \"jest --watch\",\n\t\t\"test:cov\": \"jest --coverage\",\n\t\t\"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n\t\t\"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n\t\t\"webpack\": \"NODE_ENV=development nest build --watch --webpack\",\n\t\t\"start:hmr\": \"node dist/main\",\n\t\t\"heroku-postbuild\": \"npm i --only=dev --no-shrinkwrap && npm run build\",\n\t\t\"doc\": \"npx compodoc --port 11045 -p tsconfig.json -s\",\n\t\t\"doc:serve\": \"npm run doc && npx compodoc -s\"\n\t},\n\t\"dependencies\": {\n\t\t\"@godaddy/terminus\": \"^4.2.1\",\n\t\t\"@nestjs/common\": \"^6.7.2\",\n\t\t\"@nestjs/core\": \"^6.7.2\",\n\t\t\"@nestjs/jwt\": \"^6.1.1\",\n\t\t\"@nestjs/passport\": \"^6.1.0\",\n\t\t\"@nestjs/platform-express\": \"^6.9.0\",\n\t\t\"@nestjs/platform-socket.io\": \"^6.9.0\",\n\t\t\"@nestjs/serve-static\": \"^1.0.1\",\n\t\t\"@nestjs/swagger\": \"^3.1.0\",\n\t\t\"@nestjs/terminus\": \"^6.5.2\",\n\t\t\"@nestjs/typeorm\": \"^6.2.0\",\n\t\t\"@nestjs/websockets\": \"^6.9.0\",\n\t\t\"@nestjsx/crud\": \"^4.2.0\",\n\t\t\"@nestjsx/crud-typeorm\": \"^4.2.0\",\n\t\t\"@types/mongodb\": \"^3.3.8\",\n\t\t\"bcrypt\": \"^3.0.6\",\n\t\t\"cache-manager\": \"^2.10.0\",\n\t\t\"class-transformer\": \"^0.2.3\",\n\t\t\"class-validator\": \"^0.11.0\",\n\t\t\"cloudinary\": \"1.16.0\",\n\t\t\"dotenv\": \"^8.2.0\",\n\t\t\"express-rate-limit\": \"^5.0.0\",\n\t\t\"geolib\": \"^3.1.0\",\n\t\t\"googleapis\": \"^45.0.0\",\n\t\t\"handlebars\": \"^4.5.2\",\n\t\t\"helmet\": \"^3.21.2\",\n\t\t\"http\": \"^0.0.0\",\n\t\t\"https\": \"^1.0.0\",\n\t\t\"mongodb\": \"^3.3.3\",\n\t\t\"nodemailer\": \"^6.3.1\",\n\t\t\"passport\": \"^0.4.0\",\n\t\t\"passport-facebook-token\": \"^3.3.0\",\n\t\t\"passport-google-oauth20\": \"^2.0.0\",\n\t\t\"passport-jwt\": \"^4.0.0\",\n\t\t\"passport-local\": \"^1.0.0\",\n\t\t\"reflect-metadata\": \"^0.1.13\",\n\t\t\"rimraf\": \"^3.0.0\",\n\t\t\"rxjs\": \"^6.5.3\",\n\t\t\"speakeasy\": \"^2.0.0\",\n\t\t\"swagger-ui-express\": \"^4.1.2\",\n\t\t\"typeorm\": \"^0.2.20\",\n\t\t\"uuid\": \"^3.3.3\",\n\t\t\"webpack-bundle-analyzer\": \"^3.6.0\",\n\t\t\"winston\": \"^3.2.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@compodoc/compodoc\": \"^1.1.11\",\n\t\t\"@nestjs/cli\": \"^6.9.0\",\n\t\t\"@nestjs/schematics\": \"^6.7.0\",\n\t\t\"@nestjs/testing\": \"^6.7.1\",\n\t\t\"@types/bcrypt\": \"^3.0.0\",\n\t\t\"@types/dotenv\": \"^8.2.0\",\n\t\t\"@types/express\": \"^4.17.1\",\n\t\t\"@types/jest\": \"^24.0.18\",\n\t\t\"@types/node\": \"^12.7.5\",\n\t\t\"@types/passport-facebook-token\": \"^0.4.33\",\n\t\t\"@types/passport-jwt\": \"^3.0.2\",\n\t\t\"@types/passport-local\": \"^1.0.33\",\n\t\t\"@types/socket.io\": \"^2.1.4\",\n\t\t\"@types/speakeasy\": \"^2.0.5\",\n\t\t\"@types/supertest\": \"^2.0.8\",\n\t\t\"jest\": \"^24.9.0\",\n\t\t\"prettier\": \"^1.18.2\",\n\t\t\"progress-bar-webpack-plugin\": \"^1.12.1\",\n\t\t\"supertest\": \"^4.0.2\",\n\t\t\"ts-jest\": \"^24.1.0\",\n\t\t\"ts-loader\": \"^6.1.1\",\n\t\t\"ts-node\": \"^8.4.1\",\n\t\t\"tsconfig-paths\": \"^3.9.0\",\n\t\t\"tslint\": \"^5.20.0\",\n\t\t\"typescript\": \"^3.6.3\",\n\t\t\"webpack-node-externals\": \"^1.7.2\"\n\t},\n\t\"jest\": {\n\t\t\"moduleFileExtensions\": [\n\t\t\t\"js\",\n\t\t\t\"json\",\n\t\t\t\"ts\"\n\t\t],\n\t\t\"rootDir\": \"src\",\n\t\t\"testRegex\": \".spec.ts$\",\n\t\t\"transform\": {\n\t\t\t\"^.+\\\\.(t|j)s$\": \"ts-jest\"\n\t\t},\n\t\t\"coverageDirectory\": \"./coverage\",\n\t\t\"testEnvironment\": \"node\"\n\t}\n}\n"
  },
  {
    "path": "src/app.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\ndescribe('AppController', () => {\n  let appController: AppController;\n\n  beforeEach(async () => {\n    const app: TestingModule = await Test.createTestingModule({\n      controllers: [AppController],\n      providers: [AppService],\n    }).compile();\n\n    appController = app.get<AppController>(AppController);\n  });\n\n  describe('root', () => {\n    it('should return \"Hello World!\"', () => {\n      expect(appController.getHello()).toBe('Hello World!');\n    });\n  });\n});\n"
  },
  {
    "path": "src/app.controller.ts",
    "content": "import {\n\tController,\n\tGet,\n\tRequest,\n\tPost,\n\tUseGuards,\n\tParam,\n\tRes,\n\tUseInterceptors,\n\tUploadedFile,\n\tCacheInterceptor,\n\tBody,\n\tQuery,\n\tLogger\n} from '@nestjs/common'\nimport { AuthGuard } from '@nestjs/passport'\nimport {\n\tApiBearerAuth,\n\tApiConsumes,\n\tApiImplicitFile,\n\tApiImplicitBody,\n\tApiUseTags,\n\tApiOperation,\n\tApiResponse,\n\tApiImplicitQuery\n} from '@nestjs/swagger'\nimport { FileInterceptor } from '@nestjs/platform-express'\nimport chalk from 'chalk'\nimport { AppService } from './app.service'\nimport { AuthService } from './auth/auth.service'\nimport { LoginUserDto } from './modules/users/dto/login-user.dto'\nimport { STATIC, SSL } from './environments'\nimport { uploadFile } from './shared/upload'\nimport { LoginResponseDto } from './modules/users/dto/login-response.dto'\nimport { ErrorResponseDto } from './modules/users/dto/error-response.dto'\nimport { UserEntity } from './modules/users/user.entity'\nimport { UploadResponseDto } from './modules/users/dto/upload-response.dto'\nimport { DealsService } from './modules/deals/deals.service'\nimport { DealResponseDto } from './modules/deals/dto/deal-response.dto'\nimport { DealType } from './modules/deals/enum/deal.enum'\n\n@ApiResponse({\n\tstatus: 401,\n\tdescription: 'Unauthorized.',\n\ttype: ErrorResponseDto\n})\n@ApiResponse({ status: 403, description: 'Forbidden.', type: ErrorResponseDto })\n@ApiUseTags('basic')\n@Controller()\n@UseInterceptors(CacheInterceptor)\nexport class AppController {\n\tconstructor(\n\t\tprivate readonly appService: AppService,\n\t\tprivate readonly authService: AuthService,\n\t\tprivate readonly dealService: DealsService\n\t) {}\n\n\t@Get()\n\tgetHello(): string {\n\t\treturn this.appService.getHello()\n\t}\n\n\t@Post('/req')\n\tpostHello(@Request() req) {\n\t\tLogger.log(`🤬 ${chalk.hex('#87e8de').bold(`${req.body}`)}`, 'Check')\n\t\treturn req.body\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: LoginResponseDto\n\t})\n\t@UseGuards(AuthGuard('local'))\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one Acess token 👻'\n\t})\n\t@Post('login')\n\t@ApiImplicitBody({ name: 'input', type: LoginUserDto })\n\tlogin(@Request() req): Promise<LoginResponseDto> {\n\t\treturn this.authService.login(req.user)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found profile',\n\t\ttype: UserEntity\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one Profile 👻'\n\t})\n\t@Get('profile')\n\tgetProfile(@Request() req) {\n\t\treturn req.user\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [DealResponseDto]\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one My deal 👻'\n\t})\n\t@Get('myDeal')\n\t@ApiImplicitQuery({\n\t\tname: 'dealType',\n\t\tdescription: 'The dealType of the Deal',\n\t\trequired: false,\n\t\ttype: DealType,\n\t\tenum: ['Request', 'Offer']\n\t})\n\tgetMyDeal(@Request() req, @Query() query) {\n\t\tconst myDeal = this.dealService.findByUserId(req, query)\n\t\treturn myDeal\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 201,\n\t\tdescription: 'The record has been successfully created.',\n\t\ttype: UploadResponseDto\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Create one File 👻'\n\t})\n\t@Post('upload')\n\t@ApiConsumes('multipart/form-data')\n\t@ApiImplicitFile({\n\t\tname: 'file',\n\t\trequired: true\n\t})\n\t@UseInterceptors(FileInterceptor('file'))\n\tasync uploadFile(@UploadedFile() file): Promise<UploadResponseDto> {\n\t\tconst url = await uploadFile(file)\n\n\t\treturn { url }\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Files',\n\t\tdeprecated: true\n\t})\n\t@Post('uploads')\n\t@UseInterceptors(FileInterceptor('files'))\n\t@ApiConsumes('multipart/form-data')\n\t@ApiImplicitFile({\n\t\tname: 'files',\n\t\trequired: true,\n\t\tdescription: 'List of files.'\n\t})\n\tuploadFiles(@UploadedFile() files: any) {\n\t\t// console.log(files);\n\t\treturn ['path', 'path1']\n\t}\n\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one File'\n\t\t// deprecated: true\n\t})\n\t@Get(`${STATIC!}/:fileId`)\n\tgetUpload(@Param('fileId') fileId: string, @Res() res): any {\n\t\treturn res.sendFile(fileId, {\n\t\t\troot: `${STATIC!}`\n\t\t})\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Verify one Ssl',\n\t\tdeprecated: true\n\t})\n\t@Get(`${SSL!}/:fileId`)\n\tgetSSLKey(@Param('fileId') fileId: string, @Res() res): any {\n\t\treturn res.sendFile(fileId, {\n\t\t\troot: `${SSL!}`\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/app.module.ts",
    "content": "import { Module, CacheModule, OnModuleInit } from '@nestjs/common'\nimport { TypeOrmModule } from '@nestjs/typeorm'\nimport { ServeStaticModule } from '@nestjs/serve-static'\nimport { join } from 'path'\nimport { TerminusModule } from '@nestjs/terminus'\n\nimport { AppController } from './app.controller'\nimport { AppService } from './app.service'\n\nimport { CacheService, TypeormService } from './config'\nimport { UsersModule } from './modules/users/users.module'\nimport { AuthModule } from './auth/auth.module'\nimport { TerminusOptionsService } from './terminus-options.service'\nimport { EventsModule } from './modules/events/events.module'\nimport { EventsGateway } from './modules/events/events.gateway'\nimport { STATIC } from './environments'\nimport { DealsModule } from './modules/deals/deals.module'\nimport { BiddersModule } from './modules/bidders/bidders.module'\nimport { AddressesModule } from './modules/addresses/addresses.module'\nimport { ConnectionsModule } from './modules/connections/connections.module'\nimport { BannersModule } from './modules/banners/banners.module'\nimport { ClassesModule } from './modules/classes/classes.module'\nimport { StudentsModule } from './modules/students/students.module'\nimport { AttendanceModule } from './modules/attendance/attendance.module'\nimport { ChatsModule } from './modules/chats/chats.module'\nimport { ChatsGateway } from './modules/chats/chats.gateway'\n\n@Module({\n\timports: [\n\t\tTypeOrmModule.forRootAsync({\n\t\t\tuseClass: TypeormService\n\t\t}),\n\t\tCacheModule.registerAsync({\n\t\t\tuseClass: CacheService\n\t\t}),\n\t\tServeStaticModule.forRoot({\n\t\t\trootPath: join(__dirname, '..', STATIC)\n\t\t}),\n\t\tServeStaticModule.forRoot({\n\t\t\trootPath: join(__dirname, '..', '.well-known/acme-challenge')\n\t\t}),\n\t\tTerminusModule.forRootAsync({\n\t\t\tuseClass: TerminusOptionsService\n\t\t}),\n\t\tAuthModule,\n\t\tUsersModule,\n\t\tAddressesModule,\n\t\tDealsModule,\n\t\tConnectionsModule,\n\t\tEventsModule,\n\t\tBiddersModule,\n\t\tBannersModule,\n\t\tClassesModule,\n\t\tStudentsModule,\n\t\tAttendanceModule,\n\t\tChatsModule\n\t],\n\tcontrollers: [AppController],\n\tproviders: [AppService, EventsGateway, ChatsGateway]\n})\nexport class AppModule implements OnModuleInit {\n\tonModuleInit() {\n\t\tconsole.log('The module has been initialized.')\n\t}\n}\n"
  },
  {
    "path": "src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common'\n\n@Injectable()\nexport class AppService {\n\tgetHello() {\n\t\treturn 'Hello World!'\n\t}\n}\n"
  },
  {
    "path": "src/assets/templates/udacity-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<title>Verify Your Email on {{ author }}</title>\n\t</head>\n\n\t<body>\n\t\t<head>\n\t\t\t<!--[if gte mso 9\n\t\t\t\t]><xml>\n\t\t\t\t\t<o:OfficeDocumentSettings>\n\t\t\t\t\t\t<o:AllowPNG />\n\t\t\t\t\t\t<o:PixelsPerInch>96</o:PixelsPerInch>\n\t\t\t\t\t</o:OfficeDocumentSettings>\n\t\t\t\t</xml><!\n\t\t\t[endif]-->\n\t\t\t<title>{{ author }}_email</title>\n\t\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n\t\t\t<meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\" />\n\t\t\t<!--[if !mso]><!-- -->\n\t\t\t<meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\" />\n\t\t\t<!--<![endif]-->\n\t\t\t<!--[if !mso]><!-- -->\n\t\t\t<link\n\t\t\t\thref=\"https://fonts.googleapis.com/css?family=Open+Sans:600,400,300\"\n\t\t\t\trel=\"stylesheet\"\n\t\t\t\ttype=\"text/css\"\n\t\t\t/>\n\t\t\t<!--<![endif]-->\n\t\t\t<style type=\"text/css\">\n\t\t\t\thtml,\n\t\t\t\tbody {\n\t\t\t\t\tbackground-color: #fafbfc;\n\t\t\t\t}\n\n\t\t\t\timg {\n\t\t\t\t\tdisplay: block;\n\t\t\t\t}\n\n\t\t\t\t.ReadMsgBody {\n\t\t\t\t\twidth: 100%;\n\t\t\t\t}\n\n\t\t\t\t.ExternalClass {\n\t\t\t\t\twidth: 100%;\n\t\t\t\t}\n\n\t\t\t\t* {\n\t\t\t\t\t-webkit-text-size-adjust: none;\n\t\t\t\t}\n\n\t\t\t\t.whiteLinks a:link,\n\t\t\t\t.whiteLinks a:visited {\n\t\t\t\t\tcolor: #ffffff !important;\n\t\t\t\t}\n\n\t\t\t\t.appleLinksGrey a {\n\t\t\t\t\tcolor: #b7bdc1 !important;\n\t\t\t\t\ttext-decoration: none !important;\n\t\t\t\t}\n\n\t\t\t\ttable {\n\t\t\t\t\tborder-collapse: collapse;\n\t\t\t\t}\n\n\t\t\t\t.preheader {\n\t\t\t\t\tfont-size: 1px;\n\t\t\t\t\tline-height: 1px;\n\t\t\t\t\tdisplay: none !important;\n\t\t\t\t\tmso-hide: all;\n\t\t\t\t}\n\n\t\t\t\t/* AOL Mail td overrides */\n\t\t\t\t#maincontent td {\n\t\t\t\t\tcolor: #525c65;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t<!--[if mso]>\n\t\t\t\t<style type=\"text/css\">\n\t\t\t\t\tbody,\n\t\t\t\t\ttable,\n\t\t\t\t\ttd,\n\t\t\t\t\ta {\n\t\t\t\t\t\tfont-family: Arial, Helvetica, sans-serif !important;\n\t\t\t\t\t}\n\t\t\t\t</style>\n\t\t\t<![endif]-->\n\t\t</head>\n\n\t\t<body bgcolor=\"#fafbfc\" style=\"Margin:0; padding:0;\" yahoo=\"fix\">\n\t\t\t<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td style=\"background-color:#fafbfc\">\n\t\t\t\t\t\t\t<center\n\t\t\t\t\t\t\t\tbgcolor=\"#fafbfc\"\n\t\t\t\t\t\t\t\tstyle=\"width:100%;background-color:#fafbfc;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tid=\"maincontent\"\n\t\t\t\t\t\t\t\t\tstyle=\"max-width:620px; font-size:0;margin:0 auto;\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclass=\"preheader\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"font-size: 1px; line-height:1px; display: none!important; mso-hide:all;\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tOne more step to get started\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n              <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"width:620px;\">\n                <tr>\n                  <td valign=\"top\">\n            <![endif]-->\n\n\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"width:100%;\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:100%;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\" style=\"padding-bottom:20px;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"font-family:'Open+Sans', 'Open Sans', Helvetica, Arial, sans-serif; font-size:13px; line-height:18px; color:#00C0EA; text-align:center;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td style=\"padding:20px 0 10px 0;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref=\"{{ issuer }}\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"text-decoration:none;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"{{ author }}\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"50\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:unique@kreata.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; font-family:'Open+Sans', 'Open Sans', Helvetica, Arial, sans-serif; font-size:22px; line-height:26px; color:#000000; text-transform:uppercase; text-align:center; letter-spacing:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"50\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:100%;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#fafbfc\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:7px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#f5f6f7\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:1px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#f0f2f3\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:1px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#edeef1\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:1px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td bgcolor=\"#ffffff\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:100%;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"text-align:center; padding:40px 40px 40px 40px; border-top:3px solid #5A71AF;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n                              <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"width:520px;\">\n                                <tr>\n                                  <td valign=\"top\">\n                            <![endif]-->\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:inline-block; width:100%; max-width:520px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"font-family:'Open+Sans', 'Open Sans', Helvetica, Arial, sans-serif; font-size:14px; line-height:24px; color:#525C65; text-align:left; width:100%;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"Margin:0; font-size:18px; line-height:23px; color:#102231; font-weight:bold;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<strong>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tHi {{ to }},</strong\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><br /><br />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ text1 }}<br /><br />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talign=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"padding:15px 0 40px 0; border-bottom:1px solid #f3f6f9; \"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"border-collapse:separate !important; border-radius:15px; width:210px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talign=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvalign=\"top\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n\t\t\t\t\t<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" style=\"width:210px\">\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td bgcolor=\"#01b3e3\" style=\"padding:0px 10px; text-align:center;\" valign=\"top\">\n\t\t\t\t<![endif]-->\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"background-color:#5A71AF; border-collapse:separate !important; border-top:10px solid #5A71AF; border-bottom:10px solid #5A71AF; border-right:45px solid #5A71AF; border-left:45px solid #5A71AF; border-radius:4px; color:#ffffff; display:inline-block; font-family:'Open+Sans','Open Sans',Helvetica, Arial, sans-serif; font-size:13px; font-weight:bold; text-align:center; text-decoration:none; letter-spacing:2px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>{{ button }}</a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</table>\n\t\t\t\t<![endif]-->\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td style=\"padding-top:30px;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"Margin:20px 0 20px 0;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ text2 }}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"font:14px/16px Arial, Helvetica, sans-serif; color:#363636; padding:0 0 14px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCheers,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"font:bold 14px/16px Arial, Helvetica, sans-serif; color:#363636; padding:0 0 7px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ author }}'s Team\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n                                    </td>\n                                  </tr>\n                                </table>\n                              <![endif]-->\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#e0e2e5\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"height:1px; width:100%; line-height:1px; font-size:0;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#e0e2e4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"height:1px; width:100%; line-height:1px; font-size:0;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#e8ebed\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"height:1px; width:100%; line-height:1px; font-size:0;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#f1f3f6\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"height:1px; width:100%; line-height:1px; font-size:0;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#edeef1\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:1px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#f0f2f3\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:1px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#f5f6f7\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:1px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#fafbfc\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:7px; font-size:1px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t<td style=\"text-align:center; padding:0;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n                  <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"width:520px;\">\n                    <tr>\n                      <td valign=\"top\">\n                <![endif]-->\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:inline-block; width:100%; max-width:520px; vertical-align:top;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:100%;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talign=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"padding:30px 0; border-bottom:1px solid #e5ebef;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:265px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ ios }}\" target=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"IOS\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"44\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:ios@chnirt.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; width:120px!important;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"120\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref=\"{{ android }}\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"Android\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"44\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:android@chnirt.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; width:120px!important;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"120\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n                        </td>\n                      </tr>\n                    </table>\n                  <![endif]-->\n\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\" style=\"padding:30px 0 20px 0;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"width:220px;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ twitter }}\" target=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"Twitter\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:twitter@chnirt.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; width:26px!important; height:26px!important;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ facebook }}\" target=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"Facebook\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:facebook@chnirt.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; width:26px!important; height:26px!important;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ googleplus }}\" target=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"Google\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:googleplus@chnirt.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; width:28px!important; height:26px!important;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"28\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ linkedin }}\" target=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t><img\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talt=\"Linkedin\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsrc=\"cid:linkedin@chnirt.ee\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"display:block; width:26px!important; height:26px!important;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"26\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/></a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t<td align=\"center\" style=\"padding-bottom:40px;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"font-family:'Open+Sans', 'Open Sans', Helvetica, Arial, sans-serif; font-size:12px; line-height:18px;  text-align:center; width:auto;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td style=\"color:#b7bdc1;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p style=\"Margin:0;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"appleLinksGrey\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>{{ number }} {{ street }} St.</span\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&nbsp;•&nbsp;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"appleLinksGrey\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>{{ city }} City, {{ country }}</span\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t<!--[if gte mso 9]>\n                </td>\n              </tr>\n            </table>\n          <![endif]-->\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<div style=\" width:100%;\">\n\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"width:100%;\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\t\talign=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tbgcolor=\"#7d97ad\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"padding:10px 0;\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellpadding=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellspacing=\"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"font-family:'Open+Sans', 'Open Sans', Helvetica, Arial, sans-serif; font-size:14px; line-height:19px;  text-align:center; width:auto;\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<td style=\"color:#ffffff;\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tBe in demand\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</center>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</body>\n\t</body>\n</html>\n"
  },
  {
    "path": "src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common'\nimport { JwtModule } from '@nestjs/jwt'\nimport { PassportModule } from '@nestjs/passport'\nimport { AuthService } from './auth.service'\n// import { UsersModule } from '../modules/users/users.module'\nimport { LocalStrategy } from './local.strategy'\nimport { JwtStrategy } from './jwt.strategy'\nimport { ACCESS_TOKEN_SECRET } from '../environments'\n\n@Module({\n\timports: [\n\t\t// UsersModule,\n\t\tPassportModule.register({ defaultStrategy: 'jwt', session: true }),\n\t\tJwtModule.register({\n\t\t\tsecret: ACCESS_TOKEN_SECRET!,\n\t\t\tsignOptions: { expiresIn: '30d' }\n\t\t})\n\t],\n\tproviders: [AuthService, LocalStrategy, JwtStrategy],\n\texports: [AuthService]\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "src/auth/auth.service.ts",
    "content": "import { Injectable } from '@nestjs/common'\nimport { JwtService } from '@nestjs/jwt'\nimport { comparePassword } from '../utils'\nimport { UserEntity } from '../modules/users/user.entity'\nimport { LoginResponseDto } from 'modules/users/dto/login-response.dto'\nimport { getMongoRepository } from 'typeorm'\n\n@Injectable()\nexport class AuthService {\n\tconstructor(private readonly jwtService: JwtService) {}\n\n\tasync validateUser(email: string, password: string): Promise<any> {\n\t\tconst user = await getMongoRepository(UserEntity).findOne({\n\t\t\twhere: {\n\t\t\t\temail\n\t\t\t}\n\t\t})\n\n\t\tif (user && (await comparePassword(password, user.password))) {\n\t\t\t// tslint:disable-next-line: no-shadowed-variable\n\t\t\tconst { password, ...result } = user\n\n\t\t\treturn result\n\t\t}\n\n\t\treturn null\n\t}\n\n\tasync login(user: UserEntity): Promise<LoginResponseDto> {\n\t\tconst { _id } = user\n\t\tconst payload = { sub: _id }\n\t\tconst expiresIn = 60 * 60 * 24 * 30\n\n\t\treturn {\n\t\t\taccessToken: this.jwtService.sign(payload, {\n\t\t\t\texpiresIn\n\t\t\t}),\n\t\t\tuser,\n\t\t\texpiresIn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/auth/facebook.strategy.ts",
    "content": "// import { Injectable } from \"@nestjs/common\";\n\n// @Injectable()\n// export class FacebookStrategy {\n//   constructor(\n//     private readonly userService: UserService,\n//   ) {\n//     this.init();\n//   }\n//   init() {\n//     use(\n//       new FacebookTokenStrategy(\n//         {\n//           clientID: <YOUR_APP_CLIENT_ID>,\n//           clientSecret: <YOUR_APP_CLIENT_SECRET>,\n//           fbGraphVersion: 'v3.0',\n//         },\n//         async (\n//           accessToken: string,\n//           refreshToken: string,\n//           profile: any,\n//           done: any,\n//         ) => {\n//           const user = await this.userService.findOrCreate(\n//             profile,\n//           );\n//           return done(null, user);\n//         },\n//       ),\n//     );\n//   }\n// }\n"
  },
  {
    "path": "src/auth/google.strategy.ts",
    "content": "// import { Injectable } from '@nestjs/common'\n// import { PassportStrategy } from '@nestjs/passport'\n// import { Strategy } from 'passport-google-oauth20'\n// import { AuthService, Provider } from './auth.service'\n\n// @Injectable()\n// export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {\n// \tconstructor(private readonly authService: AuthService) {\n// \t\tsuper({\n// \t\t\tclientID: 'MY_CLIENT_ID', // Not my real client secret, see your own application credentials at Google!\n// \t\t\tclientSecret: 'MY_CLIENT_SECRET', // Not my real client secret, see your own application credentials at Google!\n// \t\t\tcallbackURL: 'http://localhost:3000/auth/google/callback',\n// \t\t\tpassReqToCallback: true,\n// \t\t\tscope: ['profile']\n// \t\t})\n// \t}\n\n// \tasync validate(\n// \t\trequest: any,\n// \t\taccessToken: string,\n// \t\trefreshToken: string,\n// \t\tprofile,\n// \t\tdone: any\n// \t) {\n// \t\ttry {\n// \t\t\tconsole.log(profile)\n\n// \t\t\tconst jwt: string = await this.authService.validateOAuthLogin(\n// \t\t\t\tprofile.id,\n// \t\t\t\tProvider.GOOGLE\n// \t\t\t)\n// \t\t\tconst user = {\n// \t\t\t\tjwt\n// \t\t\t}\n\n// \t\t\tdone(null, user)\n// \t\t} catch (err) {\n// \t\t\t// console.log(err)\n// \t\t\tdone(err, false)\n// \t\t}\n// \t}\n// }\n"
  },
  {
    "path": "src/auth/jwt.strategy.ts",
    "content": "import { ExtractJwt, Strategy } from 'passport-jwt'\nimport { PassportStrategy } from '@nestjs/passport'\nimport { Injectable, UnauthorizedException } from '@nestjs/common'\nimport { ACCESS_TOKEN_SECRET } from '../environments'\nimport { getMongoRepository } from 'typeorm'\nimport { UserEntity } from '../modules/users/user.entity'\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n\tconstructor() {\n\t\tsuper({\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\tignoreExpiration: false,\n\t\t\tsecretOrKey: ACCESS_TOKEN_SECRET!\n\t\t})\n\t}\n\n\tasync validate(payload: any) {\n\t\ttry {\n\t\t\tconst { sub } = payload\n\n\t\t\tconst user = await getMongoRepository(UserEntity).findOne({ _id: sub })\n\n\t\t\tconst { password, ...result } = user\n\n\t\t\treturn result\n\t\t} catch (err) {\n\t\t\tthrow new UnauthorizedException('Email or password is incorrect.')\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/auth/local.strategy.ts",
    "content": "import { Strategy } from 'passport-local'\nimport { PassportStrategy } from '@nestjs/passport'\nimport { Injectable, UnauthorizedException } from '@nestjs/common'\nimport { AuthService } from './auth.service'\n\n@Injectable()\nexport class LocalStrategy extends PassportStrategy(Strategy) {\n\tconstructor(private readonly authService: AuthService) {\n\t\tsuper({\n\t\t\tusernameField: 'email',\n\t\t\tpasswordField: 'password'\n\t\t})\n\t}\n\n\tasync validate(username: string, password: string): Promise<any> {\n\t\ttry {\n\t\t\tconst user = await this.authService.validateUser(username, password)\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new UnauthorizedException('Email or password is incorrect.')\n\t\t\t}\n\n\t\t\treturn user\n\t\t} catch (err) {\n\t\t\tthrow new UnauthorizedException('Email or password is incorrect.')\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/common/filters/http-exception.filter.ts",
    "content": "import {\n\tArgumentsHost,\n\tCatch,\n\tExceptionFilter,\n\tHttpException\n} from '@nestjs/common'\n\n@Catch(HttpException)\nexport class HttpExceptionFilter implements ExceptionFilter<HttpException> {\n\tcatch(exception: HttpException, host: ArgumentsHost) {\n\t\tconst ctx = host.switchToHttp()\n\t\tconst response = ctx.getResponse()\n\t\tconst request = ctx.getRequest()\n\t\tconst statusCode = exception.getStatus()\n\n\t\tresponse.status(statusCode).json({\n\t\t\tstatusCode,\n\t\t\tmessage: exception.message.message || exception.message.error,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tpath: request.url\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/common/index.ts",
    "content": "export * from './filters/http-exception.filter'\nexport * from './interceptors/exception.interceptor'\nexport * from './interceptors/http-cache.interceptor'\nexport * from './interceptors/logging.interceptor'\nexport * from './interceptors/timeout.interceptor'\nexport * from './interceptors/transform.interceptor'\nexport * from './middleware/logger.middleware'\nexport * from './pipes/validation.pipe'\n// export * from './wiston'\n"
  },
  {
    "path": "src/common/interceptors/exception.interceptor.ts",
    "content": "import {\n  CallHandler,\n  ExecutionContext,\n  HttpException,\n  HttpStatus,\n  Injectable,\n  NestInterceptor,\n} from '@nestjs/common';\nimport { Observable, throwError } from 'rxjs';\nimport { catchError } from 'rxjs/operators';\n\n@Injectable()\nexport class ErrorsInterceptor implements NestInterceptor {\n  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n    return next\n      .handle()\n      .pipe(\n        catchError(err =>\n          throwError(new HttpException('New message', HttpStatus.BAD_GATEWAY)),\n        ),\n      );\n  }\n}\n"
  },
  {
    "path": "src/common/interceptors/http-cache.interceptor.ts",
    "content": "import { CacheInterceptor, ExecutionContext, Injectable } from '@nestjs/common'\n\n@Injectable()\nclass HttpCacheInterceptor extends CacheInterceptor {\n\ttrackBy(context: ExecutionContext): string | undefined {\n\t\tconst request = context.switchToHttp().getRequest()\n\t\tconst httpServer = request.applicationRef\n\n\t\tconst isGetRequest = httpServer.getRequestMethod(request) === 'GET'\n\t\tconst excludePaths = []\n\t\tif (\n\t\t\t!isGetRequest ||\n\t\t\t(isGetRequest && excludePaths.includes(httpServer.getRequestUrl))\n\t\t) {\n\t\t\treturn undefined\n\t\t}\n\t\treturn httpServer.getRequestUrl(request)\n\t}\n}\n"
  },
  {
    "path": "src/common/interceptors/logging.interceptor.ts",
    "content": "import {\n  CallHandler,\n  ExecutionContext,\n  Injectable,\n  NestInterceptor,\n  Logger,\n} from '@nestjs/common';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\nimport chalk from 'chalk';\n\n@Injectable()\nexport class LoggingInterceptor implements NestInterceptor {\n  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n    const parentType = chalk\n      .hex('#87e8de')\n      .bold(`${context.getArgs()[0].route.path}`);\n    const fieldName = chalk\n      .hex('#87e8de')\n      .bold(`${context.getArgs()[0].route.stack[0].method}`);\n    return next.handle().pipe(\n      tap(() => {\n        Logger.debug(`⛩  ${parentType} » ${fieldName}`, 'Restful');\n        // console.log(context.getArgs()[0]['route']);\n      }),\n    );\n  }\n}\n"
  },
  {
    "path": "src/common/interceptors/timeout.interceptor.ts",
    "content": "import {\n\tCallHandler,\n\tExecutionContext,\n\tInjectable,\n\tNestInterceptor\n} from '@nestjs/common'\nimport { Observable } from 'rxjs'\nimport { timeout } from 'rxjs/operators'\n\n@Injectable()\nexport class TimeoutInterceptor implements NestInterceptor {\n\tintercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n\t\treturn next.handle().pipe(timeout(100000))\n\t}\n}\n"
  },
  {
    "path": "src/common/interceptors/transform.interceptor.ts",
    "content": "import {\n\tCallHandler,\n\tExecutionContext,\n\tInjectable,\n\tNestInterceptor\n} from '@nestjs/common'\nimport { Observable } from 'rxjs'\nimport { map } from 'rxjs/operators'\n\nexport interface Response<T> {\n\tdata: T\n}\n\n@Injectable()\nexport class TransformInterceptor<T>\n\timplements NestInterceptor<T, Response<T>> {\n\tintercept(\n\t\tcontext: ExecutionContext,\n\t\tnext: CallHandler<T>\n\t): Observable<Response<T>> {\n\t\treturn next.handle().pipe(map(data => ({ data })))\n\t}\n}\n"
  },
  {
    "path": "src/common/middleware/logger.middleware.ts",
    "content": "// import chalk from 'chalk'\n// import { logger } from '../wiston'\nimport { Logger } from '@nestjs/common';\n\nexport function LoggerMiddleware(req, res, next) {\n  // logger.debug(`📢  ${req.headers['user-agent']}`)\n  Logger.debug(\n    `📢  ${req.headers['user-agent'].split(') ')[0]})`,\n    'Bootstrap',\n    false,\n  );\n  next();\n}\n"
  },
  {
    "path": "src/common/pipes/validation.pipe.ts",
    "content": "import {\n  Injectable,\n  PipeTransform,\n  ArgumentMetadata,\n  BadRequestException,\n} from '@nestjs/common';\nimport { validate } from 'class-validator';\nimport { plainToClass } from 'class-transformer';\n\n@Injectable()\nexport class ValidationPipe implements PipeTransform<any> {\n  async transform(value: any, { metatype }: ArgumentMetadata) {\n    // destructuring metadata\n    if (!metatype || !this.toValidate(metatype)) {\n      return value;\n    }\n    const object = plainToClass(metatype, value);\n    const errors = await validate(object);\n    if (errors.length > 0) {\n      throw new BadRequestException(\n        `Form Arguments invalid: ${this.formatErrors(errors)}`,\n      );\n    }\n    return value;\n  }\n\n  // tslint:disable-next-line:ban-types\n  private toValidate(metatype: Function): boolean {\n    // tslint:disable-next-line:ban-types\n    const types: Function[] = [String, Boolean, Number, Array, Object];\n    return !types.includes(metatype);\n  }\n\n  private formatErrors(errors: any[]) {\n    return errors\n      .map(err => {\n        // tslint:disable-next-line: forin\n        for (const property in err.constraints) {\n          return err.constraints[property];\n        }\n      })\n      .join(', ');\n  }\n}\n"
  },
  {
    "path": "src/common/wiston/index.ts",
    "content": "// import { addColors, createLogger, format, transports } from 'winston';\n\n// const { label, json, timestamp, align, printf } = format;\n\n// const config = {\n//   levels: {\n//     error: 0,\n//     debug: 1,\n//     warn: 2,\n//     data: 3,\n//     info: 4,\n//     verbose: 5,\n//     silly: 6,\n//     custom: 7,\n//   },\n//   colors: {\n//     error: 'red',\n//     debug: 'blue',\n//     warn: 'yellow',\n//     data: 'grey',\n//     info: 'green',\n//     verbose: 'cyan',\n//     silly: 'magenta',\n//     custom: 'yellow',\n//   },\n// };\n\n// // tslint:disable-next-line:no-shadowed-variable\n// const myFormat = printf(({ level, message, label, timestamp }) => {\n//   // console.log(level)\n//   return `{\\n\\tlabel: ${label},\\n\\ttimestamp: ${timestamp},\\n\\tlevel: ${level},\\n\\tmessage: ${message}\\n},`;\n// });\n\n// const logger = createLogger({\n//   level: 'error',\n//   levels: config.levels,\n//   format: format.combine(\n//     label({ label: '👻  Chnirt!' }),\n//     json(),\n//     timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\n//     align(),\n//     // prettyPrint(),\n//     // colorize(),\n//     myFormat,\n//   ),\n//   defaultMeta: { service: 'user-service' },\n//   transports: [\n//     //\n//     // - Write to all logs with level `info` and below to `combined.log`\n//     // - Write all logs error (and below) to `error.log`.\n//     //\n//     // new transports.Console(),\n//     new transports.File({\n//       filename: 'logs/info.log',\n//       level: 'info',\n//     }),\n//     new transports.File({\n//       filename: 'logs/error.log',\n//       level: 'error',\n//     }),\n//     new transports.File({\n//       filename: 'logs/warn.log',\n//       level: 'warn',\n//     }),\n//     new transports.File({\n//       filename: 'logs/debug.log',\n//       level: 'debug',\n//     }),\n//     new transports.File({\n//       filename: 'logs/verbose.log',\n//       level: 'verbose',\n//     }),\n//     // new transports.File({ filename: 'src/logs/combined.log' })\n//   ],\n// });\n\n// addColors(config.colors);\n\n// export { logger };\n"
  },
  {
    "path": "src/config/cache/index.ts",
    "content": "import {\n  Injectable,\n  CacheOptionsFactory,\n  CacheModuleOptions,\n} from '@nestjs/common';\n\n@Injectable()\nexport class CacheService implements CacheOptionsFactory {\n  createCacheOptions(): CacheModuleOptions {\n    return {\n      ttl: 5, // seconds\n      max: 10, // maximum number of items in cache\n    };\n  }\n}\n"
  },
  {
    "path": "src/config/index.ts",
    "content": "export * from './cache';\nexport * from './logger';\nexport * from './typeorm';\n"
  },
  {
    "path": "src/config/logger/index.ts",
    "content": "import { LoggerService } from '@nestjs/common'\n\nexport class MyLogger implements LoggerService {\n\tlog(message: string) {}\n\terror(message: string, trace: string) {}\n\twarn(message: string) {}\n\tdebug(message: string) {}\n\tverbose(message: string) {}\n}\n"
  },
  {
    "path": "src/config/typeorm/index.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { TypeOrmOptionsFactory, TypeOrmModuleOptions } from '@nestjs/typeorm';\nimport { getMetadataArgsStorage, createConnection } from 'typeorm';\n\nimport config from '../../config.orm';\n// import { logger } from '../../common'\n\n@Injectable()\nexport class TypeormService implements TypeOrmOptionsFactory {\n  async createTypeOrmOptions(): Promise<TypeOrmModuleOptions> {\n    const options = {\n      ...config,\n      type: 'mongodb',\n      entities: getMetadataArgsStorage().tables.map(tbl => tbl.target),\n      // migrations: ['src/modules/**/migration/*.ts'],\n      // subscribers: ['src/modules/**/subscriber/*.ts'],\n      // cli: {\n      // \tentitiesDir: 'src/modules/**/entity',\n      // \tmigrationsDir: 'src/modules/**/migration',\n      // \tsubscribersDir: 'src/modules/**/subscriber'\n      // },\n      synchronize: true,\n      useNewUrlParser: true,\n      useUnifiedTopology: true,\n      keepConnectionAlive: true,\n      logging: true,\n    };\n    createConnection(options)\n      .then(data => {\n        // logger.info(data)\n        Logger.log(`☁️  Database connected`, 'TypeORM', false);\n      })\n      .catch(err => {\n        // logger.error(err)\n        Logger.error(`❌  Database connect error`, '', 'TypeORM', false);\n      });\n\n    return options;\n  }\n}\n"
  },
  {
    "path": "src/config.orm.ts",
    "content": "import { NODE_ENV, MONGO_URL, MONGO_PORT, MONGO_DB } from './environments';\n\nconst orm = {\n  development: {\n    url: MONGO_URL!,\n  },\n  testing: {\n    url: MONGO_URL!,\n  },\n  staging: {\n    host: 'localhost',\n    port: MONGO_PORT!,\n    username: '',\n    password: '',\n    database: MONGO_DB!,\n  },\n  production: {\n    url: MONGO_URL!,\n  },\n};\n\nexport default orm[NODE_ENV!];\n"
  },
  {
    "path": "src/environments/index.ts",
    "content": "import * as dotenv from 'dotenv'\ndotenv.config()\n\n// environment\nconst NODE_ENV: string = process.env.NODE_ENV || 'development'\n\n// author\nconst AUTHOR: string = process.env.AUTHOR || 'Chnirt'\n\n// application\nconst DOMAIN: string = process.env.DOMAIN || 'localhost'\nconst PORT: number = +process.env.PORT || 14047\nconst END_POINT: string = process.env.END_POINT || 'graphql'\nconst VOYAGER: string = process.env.VOYAGER || 'voyager'\nconst FE_URL: string = process.env.FE_URL || 'xxx'\nconst RATE_LIMIT_MAX: number = +process.env.RATE_LIMIT_MAX || 10000\nconst GRAPHQL_DEPTH_LIMIT: number = +process.env.GRAPHQL_DEPTH_LIMIT || 3\n\n// static\nconst STATIC: string = process.env.STATIC || 'static'\n\n// ssl\nconst SSL: string = process.env.SSL || '.well-known/acme-challenge'\n\n// mlab\nconst MLAB_USER = process.env.MLAB_USER || 'admin'\nconst MLAB_PASS = process.env.MLAB_PASS || 'chnirt1803'\nconst MLAB_HOST = process.env.MLAB_HOST || 'ds243055.mlab.com'\nconst MLAB_PORT = +process.env.MLAB_PORT || 43055\nconst MLAB_DATABASE =\n\tprocess.env.MLAB_DATABASE || 'nestjs-restful-best-practice'\nconst MLAB_URL =\n\tprocess.env.MLAB_URL ||\n\t`mongodb://${MLAB_USER}:${MLAB_PASS}@${MLAB_HOST}:${MLAB_PORT}/${MLAB_DATABASE}`\n\n// mongodb\nconst MONGO_URL: string = process.env.MONGO_PORT\n\t? `mongodb://localhost:${process.env.MONGO_PORT}`\n\t: MLAB_URL\nconst MONGO_PORT: number = +process.env.MONGO_PORT || 11049\nconst MONGO_DB: string = process.env.MONGO_PORT ? 'chnirt-nest' : MLAB_DATABASE\n\n// jsonwebtoken\nconst ISSUER: string = process.env.ISSUER || 'http://chnirt.github.io'\nconst ACCESS_TOKEN: string = process.env.ACCESS_TOKEN || 'access-token'\nconst ACCESS_TOKEN_SECRET: string = process.env.ACCESS_TOKEN_SECRET || 'basic'\nconst REFRESH_TOKEN: string = process.env.REFRESH_TOKEN || 'refresh-token'\nconst REFRESH_TOKEN_SECRET: string =\n\tprocess.env.REFRESH_TOKEN_SECRET || 'refresh-token-key'\nconst EMAIL_TOKEN: string = process.env.EMAIL_TOKEN || 'email-token'\nconst EMAIL_TOKEN_SECRET: string =\n\tprocess.env.EMAIL_TOKEN_SECRET || 'email-token-key'\nconst RESETPASS_TOKEN: string = process.env.RESETPASS_TOKEN || 'resetpass-token'\nconst RESETPASS_TOKEN_SECRET: string =\n\tprocess.env.RESETPASS_TOKEN_SECRET || 'resetpass-token-key'\n\n// bcrypt\nconst SALT: number = +process.env.SALT || 10\n\n// nodemailer\nconst MAIL_USER: string = process.env.MAIL_USER || 'xxx'\nconst MAIL_PASS: string = process.env.MAIL_PASS || 'xxx'\n\n// cloudinary\nconst CLOUD_NAME: string = process.env.CLOUD_NAME || 'xxx'\nconst API_KEY: string = process.env.API_KEY || 'xxx'\nconst API_SECRET: string = process.env.API_SECRET || 'xxx'\n\n// speakeasy\nconst SPEAKEASY_SECRET = process.env.SPEAKEASY_SECRET || 'speakeasy-secret'\nconst SPEAKEASY_DIGITS = +process.env.SPEAKEASY_DIGITS || 6\nconst SPEAKEASY_STEP = +process.env.SPEAKEASY_STEP || 60\n\n// pubsub\nconst NOTIFICATION_SUBSCRIPTION: string = 'newNotification'\nconst USER_SUBSCRIPTION: string = 'newUser'\nconst MESSAGES_SUBSCRIPTION: string = 'newMessages'\n\n// passport\nconst GOOGLE_CLIENT_ID: string = process.env.GOOGLE_CLIENT_ID || 'xxx'\nconst GOOGLE_CLIENT_SECRET: string = process.env.GOOGLE_CLIENT_SECRET || 'xxx'\nconst GOOGLE_CALLBACK_URL: string =\n\tprocess.env.GOOGLE_CALLBACK_URL || 'auth/google/callback'\n\nconst FACEBOOK_APP_ID: string = process.env.FACEBOOK_APP_ID || 'xxx'\nconst FACEBOOK_APP_SECRET: string = process.env.FACEBOOK_APP_SECRET || 'xxx'\nconst FACEBOOK_CALLBACK_URL: string =\n\tprocess.env.FACEBOOK_CALLBACK_URL || 'auth/facebook/callback'\n\n// google cloud\nconst GOOGLE_APPLICATION_CREDENTIALS: string =\n\tprocess.env.GOOGLE_APPLICATION_CREDENTIALS || 'xxx'\n\n// stripe\nconst STRIPE_PUBLIC_KEY: string = process.env.STRIPE_PUBLIC_KEY || 'xxx'\nconst STRIPE_SECRET_KEY: string = process.env.STRIPE_SECRET_KEY || 'xxx'\nconst STRIPE_PLAN: string = process.env.STRIPE_PLAN || 'xxx'\n\n// twilio\nconst TWILIO_ACCOUNT_SID: string = process.env.TWILIO_ACCOUNT_SID || 'xxx'\nconst TWILIO_AUTH_TOKEN: string = process.env.TWILIO_AUTH_TOKEN || 'xxx'\n\nexport {\n\tNODE_ENV,\n\tAUTHOR,\n\tDOMAIN,\n\tPORT,\n\tEND_POINT,\n\tVOYAGER,\n\tFE_URL,\n\tRATE_LIMIT_MAX,\n\tGRAPHQL_DEPTH_LIMIT,\n\tSTATIC,\n\tSSL,\n\tMLAB_USER,\n\tMLAB_PASS,\n\tMLAB_HOST,\n\tMLAB_PORT,\n\tMLAB_DATABASE,\n\tMLAB_URL,\n\tMONGO_URL,\n\tMONGO_PORT,\n\tMONGO_DB,\n\tISSUER,\n\tACCESS_TOKEN,\n\tACCESS_TOKEN_SECRET,\n\tREFRESH_TOKEN,\n\tREFRESH_TOKEN_SECRET,\n\tRESETPASS_TOKEN,\n\tRESETPASS_TOKEN_SECRET,\n\tEMAIL_TOKEN,\n\tEMAIL_TOKEN_SECRET,\n\tSALT,\n\tMAIL_USER,\n\tMAIL_PASS,\n\tCLOUD_NAME,\n\tAPI_KEY,\n\tAPI_SECRET,\n\tSPEAKEASY_SECRET,\n\tSPEAKEASY_DIGITS,\n\tSPEAKEASY_STEP,\n\tUSER_SUBSCRIPTION,\n\tNOTIFICATION_SUBSCRIPTION,\n\tMESSAGES_SUBSCRIPTION,\n\tGOOGLE_CLIENT_ID,\n\tGOOGLE_CLIENT_SECRET,\n\tGOOGLE_CALLBACK_URL,\n\tFACEBOOK_APP_ID,\n\tFACEBOOK_APP_SECRET,\n\tFACEBOOK_CALLBACK_URL,\n\tGOOGLE_APPLICATION_CREDENTIALS,\n\tSTRIPE_PUBLIC_KEY,\n\tSTRIPE_SECRET_KEY,\n\tSTRIPE_PLAN,\n\tTWILIO_ACCOUNT_SID,\n\tTWILIO_AUTH_TOKEN\n}\n"
  },
  {
    "path": "src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core'\nimport { Logger, InternalServerErrorException } from '@nestjs/common'\nimport chalk from 'chalk'\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'\nimport * as bodyParser from 'body-parser'\nimport * as helmet from 'helmet'\nimport * as rateLimit from 'express-rate-limit'\nimport * as fs from 'fs'\nimport { AppModule } from './app.module'\n\nimport {\n\tValidationPipe,\n\tLoggerMiddleware,\n\tTimeoutInterceptor,\n\tLoggingInterceptor,\n\tHttpExceptionFilter\n} from './common'\nimport { MyLogger } from './config'\n\nimport { NODE_ENV, DOMAIN, PORT } from './environments'\n\ndeclare const module: any\n\nasync function bootstrap() {\n\ttry {\n\t\t// const httpsOptions = {\n\t\t// \tkey: fs.readFileSync('ssl/private.key'),\n\t\t// \tcert: fs.readFileSync('ssl/certificate.crt'),\n\t\t// \tca: fs.readFileSync('ssl/ca_bundle.crt'),\n\t\t// }\n\n\t\tconst app = await NestFactory.create(AppModule, {\n\t\t\t// httpsOptions,\n\t\t\tlogger: new MyLogger(),\n\t\t\tcors: true\n\t\t})\n\n\t\tapp.use(helmet())\n\n\t\t// body parser\n\t\tapp.use(bodyParser.json())\n\t\tapp.use(bodyParser.urlencoded())\n\t\t// app.use(bodyParser.json({ limit: '2mb' }))\n\t\t// app.use(\n\t\t// \tbodyParser.urlencoded({\n\t\t// \t\tlimit: '2mb',\n\t\t// \t\textended: true,\n\t\t// \t\tparameterLimit: 2000\n\t\t// \t})\n\t\t// )\n\n\t\tapp.use(\n\t\t\trateLimit({\n\t\t\t\twindowMs: 15 * 60 * 1000, // 15 minutes\n\t\t\t\tmax: 10000 // limit each IP to 10000 requests per windowMs\n\t\t\t})\n\t\t)\n\n\t\t// // adapter for e2e testing\n\t\tconst httpAdapter = app.getHttpAdapter()\n\n\t\t// loggerMiddleware\n\t\t// tslint:disable-next-line:no-unused-expression\n\t\tNODE_ENV !== 'testing' && app.use(LoggerMiddleware)\n\n\t\t// interceptors\n\t\t// app.useGlobalInterceptors(new LoggingInterceptor())\n\t\t// app.useGlobalInterceptors(new TimeoutInterceptor())\n\t\t// app.useGlobalFilters(new HttpExceptionFilter())\n\n\t\t// global nest setup\n\t\tapp.useGlobalPipes(new ValidationPipe())\n\n\t\t// Starts listening to shutdown hooks\n\t\tapp.enableShutdownHooks()\n\n\t\tconst options = new DocumentBuilder()\n\t\t\t.setTitle('Nestjs Restful Best Practice')\n\t\t\t.setVersion('3.0.0')\n\t\t\t// .setHost('nestjs-restful-best-practice.herokuapp.com')\n\t\t\t.setBasePath('/v1')\n\t\t\t.setDescription('built NestJS, TypeORM, MongoDB')\n\t\t\t.setTermsOfService(\n\t\t\t\t'https://github.com/chnirt/nestjs-restful-best-practice/blob/master/LICENSE'\n\t\t\t)\n\t\t\t.setContactEmail('trinhchinchin@gmail.com')\n\t\t\t.setLicense(\n\t\t\t\t'MIT License',\n\t\t\t\t'https://github.com/chnirt/nestjs-restful-best-practice/blob/master/LICENSE'\n\t\t\t)\n\t\t\t.setExternalDoc('For more information', 'http://swagger.io')\n\t\t\t.setSchemes(NODE_ENV !== 'production' ? 'http' : 'https')\n\t\t\t.addBearerAuth('Authorization', 'header')\n\t\t\t.addTag('chnirt', 'developer')\n\t\t\t.build()\n\n\t\tconst document = SwaggerModule.createDocument(app, options)\n\t\tSwaggerModule.setup('api', app, document)\n\n\t\tapp.setGlobalPrefix('/v1')\n\n\t\tconst server = await app.listen(PORT!)\n\n\t\t// hot module replacement\n\t\tif (module.hot) {\n\t\t\tmodule.hot.accept()\n\t\t\tmodule.hot.dispose(() => app.close())\n\t\t}\n\n\t\tNODE_ENV !== 'production'\n\t\t\t? Logger.log(\n\t\t\t\t\t`🚀  Server ready at https://${DOMAIN!}:${chalk\n\t\t\t\t\t\t.hex('#87e8de')\n\t\t\t\t\t\t.bold(`${PORT!}`)}`,\n\t\t\t\t\t'Bootstrap'\n\t\t\t  )\n\t\t\t: Logger.log(\n\t\t\t\t\t`🚀  Server is listening on port ${chalk\n\t\t\t\t\t\t.hex('#87e8de')\n\t\t\t\t\t\t.bold(`${PORT!}`)}`,\n\t\t\t\t\t'Bootstrap'\n\t\t\t  )\n\t} catch (error) {\n\t\t// logger.error(error)\n\t\tLogger.error(`❌  Error starting server, ${error}`, '', 'Bootstrap', false)\n\t\tprocess.exit()\n\t\tthrow new InternalServerErrorException(error)\n\t}\n}\nbootstrap().catch(e => {\n\tthrow e\n})\n"
  },
  {
    "path": "src/modules/addresses/address.entity.ts",
    "content": "import { Entity, ObjectIdColumn, Column } from 'typeorm'\nimport { uuidv4 } from '../../utils'\n// import { Exclude, plainToClass } from 'class-transformer'\nimport { ApiModelProperty } from '@nestjs/swagger'\n\nimport { Position } from '../deals/entity/position.entity'\nimport { AddressType } from './enum/address.enum'\n\n@Entity({\n\tname: 'addresses',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class AddressEntity {\n\t@ApiModelProperty({ description: 'The _id of the Address' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t@ApiModelProperty({ description: 'The name of the Address' })\n\t@Column()\n\tname: string\n\n\t@ApiModelProperty({ description: 'The addressType of the Address' })\n\t@Column()\n\taddressType: AddressType\n\n\t@ApiModelProperty({ description: 'The location of the Address' })\n\t@Column()\n\tlocation: Position\n\n\t@ApiModelProperty({ description: 'The unitNumber of the Address' })\n\t@Column()\n\tunitNumber: number\n\n\t@ApiModelProperty({ description: 'The remarks of the Address' })\n\t@Column()\n\tremarks: string\n\n\t@ApiModelProperty({ description: 'The createdBy of the Address' })\n\t@Column()\n\tcreatedBy: string\n\n\t@ApiModelProperty({ description: 'The createdAt of the Address' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the Address' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<AddressEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/addresses/addresses.controller.ts",
    "content": "import {\n\tController,\n\tPost,\n\tBody,\n\tRequest,\n\tUseGuards,\n\tGet,\n\tQuery\n} from '@nestjs/common'\nimport {\n\tApiOperation,\n\tApiBearerAuth,\n\tApiImplicitQuery,\n\tApiUseTags,\n\tApiResponse\n} from '@nestjs/swagger'\nimport { CreateAddressDto } from './dto/create-address.dto'\nimport { AddressesService, Address } from './addresses.service'\nimport { AuthGuard } from '@nestjs/passport'\nimport { ErrorResponseDto } from '../users/dto/error-response.dto'\nimport { AddressEntity } from './address.entity'\n\n@ApiBearerAuth()\n@UseGuards(AuthGuard('jwt'))\n@ApiResponse({\n\tstatus: 401,\n\tdescription: 'Unauthorized.',\n\ttype: ErrorResponseDto\n})\n@ApiResponse({ status: 403, description: 'Forbidden.', type: ErrorResponseDto })\n@ApiUseTags('addresses')\n@Controller('addresses')\nexport class AddressesController {\n\tconstructor(private readonly addressesService: AddressesService) {}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [AddressEntity]\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Addresses 👻'\n\t\t// description: 'Aaa',\n\t\t// operationId: 'aaaa'\n\t})\n\t@Get()\n\t@ApiImplicitQuery({\n\t\tname: 'limit',\n\t\tdescription: 'The maximum number of transactions to return',\n\t\trequired: false,\n\t\ttype: Number\n\t})\n\t@ApiImplicitQuery({\n\t\tname: 'offset',\n\t\tdescription: 'The maximum number of transactions to skip',\n\t\trequired: false,\n\t\ttype: Number\n\t})\n\tfindAll(@Query() query, @Request() req): Promise<Address[]> {\n\t\treturn this.addressesService.findAll(query, req)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 201,\n\t\tdescription: 'The record has been successfully created',\n\t\ttype: Boolean\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one Address 👻'\n\t})\n\t@Post()\n\tinsert(\n\t\t@Body() createAddressDto: CreateAddressDto,\n\t\t@Request() req\n\t): Promise<boolean> {\n\t\treturn this.addressesService.insert(createAddressDto, req)\n\t}\n}\n"
  },
  {
    "path": "src/modules/addresses/addresses.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AddressesController } from './addresses.controller';\nimport { AddressesService } from './addresses.service';\n\n@Module({\n  controllers: [AddressesController],\n  providers: [AddressesService]\n})\nexport class AddressesModule {}\n"
  },
  {
    "path": "src/modules/addresses/addresses.service.ts",
    "content": "import { Injectable, ForbiddenException } from '@nestjs/common'\nimport { CreateAddressDto } from './dto/create-address.dto'\nimport { AddressEntity } from './address.entity'\nimport { getMongoRepository } from 'typeorm'\n\nexport type Address = any\n\n@Injectable()\nexport class AddressesService {\n\tasync findAll(query: any, req: any): Promise<Address[]> {\n\t\tconst { offset, limit } = query\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\tconst pipelineArray = []\n\n\t\tif (offset) {\n\t\t\tif (offset < 1) {\n\t\t\t\tthrow new ForbiddenException('The offset must be greater than 0')\n\t\t\t} else {\n\t\t\t\tpipelineArray.push({\n\t\t\t\t\t$skip: +offset\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif (limit) {\n\t\t\tif (limit < 1) {\n\t\t\t\tthrow new ForbiddenException('The limit must be greater than 0')\n\t\t\t} else {\n\t\t\t\tpipelineArray.push({\n\t\t\t\t\t$limit: +limit\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst match = [\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\tcreatedBy: _id\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\tcreatedBy: 0,\n\t\t\t\t\tcreatedAt: 0,\n\t\t\t\t\tupdatedAt: 0\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tpipelineArray.push(...match)\n\n\t\treturn await getMongoRepository(AddressEntity)\n\t\t\t.aggregate(pipelineArray)\n\t\t\t.toArray()\n\t}\n\n\tasync insert(createAddressDto: CreateAddressDto, req: any): Promise<boolean> {\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\t\tconst { addressType } = createAddressDto\n\n\t\tif (addressType !== 'Others') {\n\t\t\tconst foundAddress = await getMongoRepository(AddressEntity).findOne({\n\t\t\t\taddressType,\n\t\t\t\tcreatedBy: _id\n\t\t\t})\n\n\t\t\tif (foundAddress) {\n\t\t\t\tthrow new ForbiddenException(\n\t\t\t\t\t`Address at ${addressType} already existed`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst newAddress = await getMongoRepository(AddressEntity).save(\n\t\t\tnew AddressEntity({ ...createAddressDto, createdBy: _id })\n\t\t)\n\n\t\treturn newAddress && true\n\t}\n}\n"
  },
  {
    "path": "src/modules/addresses/dto/create-address.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty, IsEnum, IsOptional } from 'class-validator'\n\nimport { AddressType } from '../enum/address.enum'\nimport { Position } from '../../deals/entity/position.entity'\n\nexport class CreateAddressDto {\n\t@ApiModelProperty({\n\t\tenum: ['Home', 'Workplace', 'Others'],\n\t\texample: 'Home',\n\t\tdescription: 'The addressType of the Address'\n\t})\n\t@IsEnum(AddressType)\n\t@IsNotEmpty()\n\treadonly addressType: AddressType\n\n\t@ApiModelProperty({\n\t\tdefault: 'Viva coffee',\n\t\texample: 'Viva coffee',\n\t\tdescription: 'The name of the Address'\n\t})\n\t@IsOptional()\n\treadonly name: string\n\n\t@ApiModelProperty({\n\t\tdefault: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\texample: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\tdescription: 'The location of the Address'\n\t})\n\t@IsNotEmpty()\n\treadonly location: Position\n\n\t@ApiModelProperty({\n\t\tdefault: 69,\n\t\texample: 69,\n\t\tdescription: 'The unitNumber of the Address'\n\t})\n\t@IsNotEmpty() // 30m 1h 1h30 2h\n\treadonly unitNumber: number\n\n\t@ApiModelProperty({\n\t\tdefault: 'Đối diện BigC',\n\t\texample: 'Đối diện BigC',\n\t\tdescription: 'The remarks of the Address'\n\t})\n\t@IsOptional()\n\treadonly remarks: string\n}\n"
  },
  {
    "path": "src/modules/addresses/dto/query-address.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger';\n\nclass QueryFilterDto {\n  @ApiModelProperty({\n    type: String,\n    example: 'age',\n  })\n  readonly field: string;\n\n  @ApiModelProperty({\n    type: String,\n    example: 'gt',\n  })\n  readonly comparator: string;\n\n  @ApiModelProperty({\n    type: Object,\n    example: 25,\n  })\n  readonly value: any;\n}\n"
  },
  {
    "path": "src/modules/addresses/enum/address.enum.ts",
    "content": "export enum AddressType {\n\tHome = 'Home',\n\tWorkplace = 'Workplace',\n\tOthers = 'Others'\n}\n"
  },
  {
    "path": "src/modules/attendance/attendance.controller.ts",
    "content": "import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common'\nimport { AttendanceService } from './attendance.service'\nimport { ApiResponse, ApiOperation, ApiUseTags } from '@nestjs/swagger'\nimport { AttendanceEntity } from './entity/attendance.entity'\nimport { ReplaceAttendanceDto } from './dto/replace-attendance.dto'\nimport { CreateAttendanceDto } from './dto/create-attendance.dto'\n\n@ApiUseTags('attendance')\n@Controller('attendance')\nexport class AttendanceController {\n\tconstructor(private readonly attendanceService: AttendanceService) {}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [AttendanceEntity]\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many attendance 👾'\n\t})\n\t@Get()\n\tfindAll() {\n\t\treturn this.attendanceService.findAll()\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: AttendanceEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one Attendance 👾'\n\t})\n\t@Post()\n\tasync insert(@Body() createAttendanceDto: CreateAttendanceDto) {\n\t\tconst newAttendance = await this.attendanceService.insert(\n\t\t\tcreateAttendanceDto\n\t\t)\n\n\t\treturn newAttendance\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: AttendanceEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one Attendance 👾'\n\t})\n\t@Get(':id')\n\tfindOne(@Param('id') id: string) {\n\t\treturn this.attendanceService.findOne(id)\n\t}\n\n\t@ApiOperation({\n\t\ttitle: 'Replace one Attendance 👾'\n\t})\n\t@Put(':id')\n\treplace(\n\t\t@Param('id') id: string,\n\t\t@Body() replaceAttendanceDto: ReplaceAttendanceDto\n\t) {\n\t\treturn this.attendanceService.findOneAndReplace(id, replaceAttendanceDto)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record is executed 👾',\n\t\ttype: Boolean\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Delete one Attendance 👾'\n\t})\n\t@Delete(':id')\n\tremove(@Param('id') id: string) {\n\t\treturn this.attendanceService.deleteOne(id)\n\t}\n}\n"
  },
  {
    "path": "src/modules/attendance/attendance.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AttendanceController } from './attendance.controller';\nimport { AttendanceService } from './attendance.service';\n\n@Module({\n  controllers: [AttendanceController],\n  providers: [AttendanceService]\n})\nexport class AttendanceModule {}\n"
  },
  {
    "path": "src/modules/attendance/attendance.service.ts",
    "content": "import {\n\tInjectable,\n\tForbiddenException,\n\tNotFoundException\n} from '@nestjs/common'\nimport { AttendanceEntity } from './entity/attendance.entity'\nimport { CreateAttendanceDto } from './dto/create-attendance.dto'\nimport { getMongoRepository } from 'typeorm'\nimport { ReplaceAttendanceDto } from './dto/replace-attendance.dto'\nimport { StudentEntity } from '../../modules/students/entity/student.entity'\n\n// let date = new Date()\n// console.log('startOfDay', date.setHours(0, 0, 0, 0))\n// console.log('endOfDay', date.setHours(23, 59, 59, 999))\n\nexport type Attendance = any\n\n@Injectable()\nexport class AttendanceService {\n\tasync findAll(): Promise<Attendance[] | undefined> {\n\t\treturn getMongoRepository(AttendanceEntity).find()\n\t}\n\n\tasync insert(\n\t\tcreateAttendanceDto: CreateAttendanceDto\n\t): Promise<Attendance | undefined> {\n\t\tconst { studentId } = createAttendanceDto\n\t\tconst foundStudent = await getMongoRepository(StudentEntity).findOne({\n\t\t\t_id: studentId\n\t\t})\n\t\tif (!foundStudent) {\n\t\t\tthrow new NotFoundException('Student not found.')\n\t\t}\n\t\tconst date = new Date()\n\t\tconst existedAttendance = await getMongoRepository(\n\t\t\tAttendanceEntity\n\t\t).findOne({\n\t\t\twhere: {\n\t\t\t\tstudentId,\n\t\t\t\tcreatedAt: {\n\t\t\t\t\t$gt: date.setHours(0, 0, 0, 0),\n\t\t\t\t\t$lt: date.setHours(23, 59, 59, 999)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tif (existedAttendance) {\n\t\t\tthrow new ForbiddenException('Attendance already existed.')\n\t\t}\n\t\tconst newAttendance = await getMongoRepository(AttendanceEntity).save(\n\t\t\tnew AttendanceEntity({\n\t\t\t\t...createAttendanceDto\n\t\t\t})\n\t\t)\n\t\treturn newAttendance\n\t}\n\tasync findOne(_id: string): Promise<Attendance | undefined> {\n\t\tconst foundAttendance = await getMongoRepository(AttendanceEntity).findOne({\n\t\t\t_id\n\t\t})\n\t\tif (!foundAttendance) {\n\t\t\tthrow new NotFoundException('Attendance not found.')\n\t\t}\n\t\treturn foundAttendance\n\t}\n\tasync findOneAndReplace(\n\t\t_id: string,\n\t\treplaceAttendanceDto: ReplaceAttendanceDto\n\t): Promise<Attendance | undefined> {\n\t\tconst foundAttendance = await getMongoRepository(AttendanceEntity).findOne({\n\t\t\t_id\n\t\t})\n\t\tif (!foundAttendance) {\n\t\t\tthrow new NotFoundException('Attendance not found.')\n\t\t}\n\t\tconst updateAttendance = await getMongoRepository(AttendanceEntity).save(\n\t\t\tnew AttendanceEntity({\n\t\t\t\t...foundAttendance,\n\t\t\t\t...replaceAttendanceDto\n\t\t\t})\n\t\t)\n\t\treturn updateAttendance\n\t}\n\tasync deleteOne(_id: string): Promise<boolean | undefined> {\n\t\tconst foundAttendance = await getMongoRepository(AttendanceEntity).findOne({\n\t\t\t_id\n\t\t})\n\t\tif (!foundAttendance) {\n\t\t\tthrow new NotFoundException('Attendance not found.')\n\t\t}\n\t\treturn (\n\t\t\t(await getMongoRepository(AttendanceEntity).delete(foundAttendance)) &&\n\t\t\ttrue\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "src/modules/attendance/dto/create-attendance.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class CreateAttendanceDto {\n\t@ApiModelProperty({\n\t\tdefault: 'xxxx-xxxx-xxxx-xxxx',\n\t\texample: 'xxxx-xxxx-xxxx-xxxx',\n\t\tdescription: 'The studentId of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly studentId: string\n\n\t@ApiModelProperty({\n\t\tdefault: true,\n\t\texample: true,\n\t\tdescription: 'The present of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly present: boolean\n}\n"
  },
  {
    "path": "src/modules/attendance/dto/replace-attendance.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class ReplaceAttendanceDto {\n\t@ApiModelProperty({\n\t\tdefault: true,\n\t\texample: true,\n\t\tdescription: 'The present of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly present: boolean\n}\n"
  },
  {
    "path": "src/modules/attendance/entity/attendance.entity.ts",
    "content": "import { Entity, Column, ObjectIdColumn } from 'typeorm'\nimport { ApiModelProperty } from '@nestjs/swagger'\nimport { uuidv4 } from '../../../utils'\n\n@Entity({\n\tname: 'attendance',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class AttendanceEntity {\n\t@ApiModelProperty({ description: 'The _id of the Attendance' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t@ApiModelProperty({ description: 'The studentId of the Attendance' })\n\t@Column()\n\tstudentId: string\n\n\t@ApiModelProperty({ description: 'The present of the Attendance' })\n\t@Column()\n\tpresent: boolean\n\n\t@ApiModelProperty({ description: 'The createdAt of the Attendance' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the Attendance' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<AttendanceEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/banners/banner.entity.ts",
    "content": "import { Entity, ObjectIdColumn, Column } from 'typeorm'\nimport { uuidv4 } from '../../utils'\nimport { ApiModelProperty } from '@nestjs/swagger'\n@Entity({\n  name: 'banners',\n  orderBy: {\n    createdAt: 'ASC'\n  }\n})\nexport class BannerEntity {\n  @ApiModelProperty({ description: 'The _id of the Banner' })\n  @ObjectIdColumn()\n  _id: string\n\n  @ApiModelProperty({ description: 'The title of the Banner' })\n  @Column()\n  title: string\n\n  @ApiModelProperty({ description: 'The imageUrl of the Banner' })\n  @Column()\n  imageUrl: string\n\n  @ApiModelProperty({ description: 'The position of the Banner' })\n  @Column()\n  position: number\n\n  @ApiModelProperty({ description: 'The detail of the Banner' })\n  @Column()\n  detail: string\n\n  @ApiModelProperty({ description: 'The published of the Banner' })\n  @Column()\n  published: boolean\n\n  @ApiModelProperty({ description: 'The createdAt of the Banner' })\n  @Column()\n  createdAt: number\n  @ApiModelProperty({ description: 'The updatedAt of the Banner' })\n  @Column()\n  updatedAt: number\n\n  constructor(partial: Partial<BannerEntity>) {\n    if (partial) {\n      Object.assign(this, partial)\n      this._id = this._id || uuidv4()\n      this.createdAt = this.createdAt || +new Date()\n      this.updatedAt = +new Date()\n    }\n  }\n}\n"
  },
  {
    "path": "src/modules/banners/banners.controller.ts",
    "content": "import { Controller, Get, Query, Post, Body, Request, UseGuards, Put, Param } from '@nestjs/common';\nimport { BannersService, Banner } from './banners.service';\nimport { ApiOperation, ApiImplicitQuery, ApiUseTags, ApiBearerAuth, ApiResponse } from '@nestjs/swagger';\nimport { CreateBannerDto } from './dto/create-banner.dto';\nimport { AuthGuard } from '@nestjs/passport';\nimport { BannerEntity } from './banner.entity';\nimport { ReplaceBannerDto } from './dto/replace-banner.dto';\nimport { ErrorResponseDto } from '../users/dto/error-response.dto';\n\n@ApiResponse({ status: 401, description: 'Unauthorized.', type: ErrorResponseDto })\n@ApiResponse({ status: 403, description: 'Forbidden.', type: ErrorResponseDto })\n@ApiUseTags('banners')\n@Controller('banners')\nexport class BannersController {\n  constructor(private readonly bannersService: BannersService) { }\n\n  @ApiResponse({\n    status: 200,\n    description: 'The found records',\n    type: [BannerEntity]\n  })\n  @ApiOperation({\n    title: 'Retrieve many Banners 👻'\n    // description: 'Aaa',\n    // operationId: 'aaaa'\n  })\n  @Get()\n  @ApiImplicitQuery({\n    name: 'limit',\n    description: 'The maximum number of transactions to return',\n    required: false,\n    type: Number\n  })\n  @ApiImplicitQuery({\n    name: 'offset',\n    description: 'The maximum number of transactions to skip',\n    required: false,\n    type: Number\n  })\n  findAll(@Query() query): Promise<Banner> {\n    return this.bannersService.findAll(query)\n  }\n\n  @ApiResponse({\n    status: 201,\n    description: 'The record has been successfully created.',\n    type: BannerEntity\n  })\n  @ApiBearerAuth()\n  @UseGuards(AuthGuard('jwt'))\n  @ApiOperation({\n    title: 'Create one Banner 👻'\n  })\n  @Post()\n  insert(@Body() createBannerDto: CreateBannerDto): Promise<boolean> {\n    return this.bannersService.insert(createBannerDto)\n  }\n\n  @ApiResponse({\n    status: 200,\n    description: 'The found record is executed',\n    type: Boolean\n  })\n  @ApiBearerAuth()\n  @UseGuards(AuthGuard('jwt'))\n  @ApiOperation({\n    title: 'Replace one Banner 👻'\n  })\n  @Put(':id')\n  replace(@Param('id') id: string, @Body() replaceBannerDto: ReplaceBannerDto): Promise<boolean> {\n    return this.bannersService.findOneAndReplace(id, replaceBannerDto)\n  }\n}\n"
  },
  {
    "path": "src/modules/banners/banners.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { BannersController } from './banners.controller';\nimport { BannersService } from './banners.service';\n\n@Module({\n  controllers: [BannersController],\n  providers: [BannersService]\n})\nexport class BannersModule {}\n"
  },
  {
    "path": "src/modules/banners/banners.service.ts",
    "content": "import {\n\tInjectable,\n\tForbiddenException,\n\tNotFoundException\n} from '@nestjs/common'\nimport { getMongoRepository } from 'typeorm'\nimport { BannerEntity } from './banner.entity'\nimport { CreateBannerDto } from './dto/create-banner.dto'\nimport { ReplaceBannerDto } from './dto/replace-banner.dto'\n\nexport type Banner = any\n\n@Injectable()\nexport class BannersService {\n\tasync findAll(query): Promise<Banner[]> {\n\t\tconst { offset, limit } = query\n\n\t\tif (offset < 1) {\n\t\t\tthrow new ForbiddenException('The offset must be greater than 0')\n\t\t}\n\n\t\tif (limit < 1) {\n\t\t\tthrow new ForbiddenException('The offset must be greater than 0')\n\t\t}\n\n\t\treturn getMongoRepository(BannerEntity).find({\n\t\t\twhere: {\n\t\t\t\tpublished: true\n\t\t\t},\n\t\t\tskip: +offset | 0,\n\t\t\ttake: +limit | 100\n\t\t})\n\t}\n\n\tasync insert(createBannerDto: CreateBannerDto): Promise<boolean> {\n\t\tconst { position } = createBannerDto\n\n\t\tconst foundBanner = await getMongoRepository(BannerEntity).findOne({\n\t\t\tposition,\n\t\t\tpublished: true\n\t\t})\n\n\t\tif (foundBanner) {\n\t\t\tthrow new ForbiddenException('Banner already published')\n\t\t}\n\n\t\tconst newAddress = await getMongoRepository(BannerEntity).save(\n\t\t\tnew BannerEntity({ ...createBannerDto })\n\t\t)\n\n\t\treturn newAddress && true\n\t}\n\n\tasync findOneAndReplace(\n\t\t_id: string,\n\t\treplaceBannerDto: ReplaceBannerDto\n\t): Promise<boolean> {\n\t\tconst { position } = replaceBannerDto\n\t\tlet foundBanner = await getMongoRepository(BannerEntity).findOne({\n\t\t\tposition,\n\t\t\tpublished: true\n\t\t})\n\n\t\tif (foundBanner) {\n\t\t\tthrow new ForbiddenException('Banner already published')\n\t\t}\n\n\t\tfoundBanner = await getMongoRepository(BannerEntity).findOne({ _id })\n\n\t\tif (!foundBanner) {\n\t\t\tthrow new NotFoundException('Banner not found')\n\t\t}\n\n\t\tconst updateBanner = await getMongoRepository(BannerEntity).save(\n\t\t\tnew BannerEntity({\n\t\t\t\t...foundBanner,\n\t\t\t\t...replaceBannerDto\n\t\t\t})\n\t\t)\n\n\t\treturn updateBanner && true\n\t}\n}\n"
  },
  {
    "path": "src/modules/banners/dto/create-banner.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport {\n\tIsNotEmpty,\n\tIsOptional,\n\tMin,\n\tMax,\n\tIsNumber,\n\tIsBoolean\n} from 'class-validator'\n\nexport class CreateBannerDto {\n\t@ApiModelProperty({\n\t\tdefault: 'Enjoy Chewapp for Free',\n\t\texample: 'Enjoy Chewapp for Free',\n\t\tdescription: 'The title of the Banner'\n\t})\n\t@IsNotEmpty()\n\treadonly title: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'https://xxxxxxxxx',\n\t\texample: 'https://xxxxxxxxx',\n\t\tdescription: 'The imageUrl of the Banner'\n\t})\n\t@IsNotEmpty()\n\treadonly imageUrl: string\n\n\t@ApiModelProperty({\n\t\tdefault: 1,\n\t\texample: 1,\n\t\tdescription: 'The position of the Banner'\n\t})\n\t@Max(20)\n\t@Min(1)\n\t@IsNumber()\n\t@IsNotEmpty()\n\treadonly position: number\n\n\t@ApiModelProperty({\n\t\tdefault: '<h1>Hello</h1>',\n\t\texample: '<h1>Hello</h1>',\n\t\tdescription: 'The detail of the Banner'\n\t})\n\t@IsOptional()\n\treadonly detail: string\n\n\t@ApiModelProperty({\n\t\tdefault: false,\n\t\texample: false,\n\t\tdescription: 'The published of the Banner'\n\t})\n\t@IsBoolean()\n\t@IsNotEmpty()\n\treadonly published: boolean\n}\n"
  },
  {
    "path": "src/modules/banners/dto/replace-banner.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty, IsOptional, Min, Max, IsNumber, IsBoolean } from 'class-validator'\n\nexport class ReplaceBannerDto {\n\n\t@ApiModelProperty({\n\t\tdefault: 'Enjoy Chewapp for Free',\n\t\texample: 'Enjoy Chewapp for Free',\n\t\tdescription: 'The title of the Banner'\n\t})\n\t@IsNotEmpty()\n\treadonly title: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'https://xxxxxxxxx',\n\t\texample: 'https://xxxxxxxxx',\n\t\tdescription: 'The imageUrl of the Banner'\n\t})\n\t@IsNotEmpty()\n\treadonly imageUrl: string\n\n\t@ApiModelProperty({\n\t\tdefault: 1,\n\t\texample: 1,\n\t\tdescription: 'The position of the Banner'\n\t})\n\t@Max(20)\n\t@Min(1)\n\t@IsNumber()\n\t@IsNotEmpty()\n\treadonly position: number\n\n\t@ApiModelProperty({\n\t\tdefault: '<h1>Hello</h1>',\n\t\texample: '<h1>Hello</h1>',\n\t\tdescription: 'The detail of the Banner'\n\t})\n\t@IsOptional()\n\treadonly detail: string\n\n\t@ApiModelProperty({\n\t\tdefault: false,\n\t\texample: false,\n\t\tdescription: 'The published of the Banner'\n\t})\n\t@IsBoolean()\n\t@IsNotEmpty()\n\treadonly published: boolean\n}\n"
  },
  {
    "path": "src/modules/bidders/bidders.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('bidders')\nexport class BiddersController {}\n"
  },
  {
    "path": "src/modules/bidders/bidders.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { BiddersService } from './bidders.service';\nimport { BiddersController } from './bidders.controller';\n\n@Module({\n  providers: [BiddersService],\n  controllers: [BiddersController]\n})\nexport class BiddersModule {}\n"
  },
  {
    "path": "src/modules/bidders/bidders.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class BiddersService {}\n"
  },
  {
    "path": "src/modules/chats/chats.gateway.ts",
    "content": "import {\n\tSubscribeMessage,\n\tWebSocketGateway,\n\tOnGatewayInit,\n\tWebSocketServer,\n\tOnGatewayConnection,\n\tOnGatewayDisconnect\n} from '@nestjs/websockets'\nimport { Logger } from '@nestjs/common'\nimport { Socket, Server } from 'socket.io'\n\n@WebSocketGateway()\nexport class ChatsGateway\n\timplements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {\n\t@WebSocketServer() server: Server\n\n\tprivate logger: Logger = new Logger('AppGateway')\n\n\t@SubscribeMessage('msgToServer')\n\thandleMessage(client: Socket, payload: string): void {\n\t\tthis.server.emit('msgToClient', payload)\n\t}\n\n\tafterInit(server: Server) {\n\t\tthis.logger.log('Init')\n\t}\n\n\thandleDisconnect(client: Socket) {\n\t\tthis.logger.log(`Client disconnected: ${client.id}`)\n\t}\n\n\thandleConnection(client: Socket, ...args: any[]) {\n\t\tthis.logger.log(`Client connected: ${client.id}`)\n\t}\n}\n"
  },
  {
    "path": "src/modules/chats/chats.module.ts",
    "content": "import { Module } from '@nestjs/common'\n\n@Module({})\nexport class ChatsModule {}\n"
  },
  {
    "path": "src/modules/classes/classes.controller.ts",
    "content": "import {\n\tController,\n\tGet,\n\tPost,\n\tPatch,\n\tDelete,\n\tParam,\n\tUseGuards,\n\tPut,\n\tBody\n} from '@nestjs/common'\nimport {\n\tApiUseTags,\n\tApiResponse,\n\tApiBearerAuth,\n\tApiOperation\n} from '@nestjs/swagger'\nimport { ClassEntity } from './entity/class.entity'\nimport { ClassesService } from './classes.service'\nimport { AuthGuard } from '@nestjs/passport'\nimport { CreateClassDto } from './dto/create-class.dto'\nimport { ReplaceClassDto } from './dto/replace-class.dto'\n\n// @ApiBearerAuth()\n// @UseGuards(AuthGuard('jwt'))\n@ApiUseTags('classes')\n@Controller('classes')\nexport class ClassesController {\n\tconstructor(private readonly classesService: ClassesService) {}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [ClassEntity]\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Classs 👾'\n\t})\n\t@Get()\n\tfindAll() {\n\t\treturn this.classesService.findAll()\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: ClassEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one Class 👾'\n\t})\n\t@Post()\n\tasync insert(@Body() createClassDto: CreateClassDto) {\n\t\tconst newClass = await this.classesService.insert(createClassDto)\n\n\t\treturn newClass\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: ClassEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one Class 👾'\n\t})\n\t@Get(':id')\n\tfindOne(@Param('id') id: string) {\n\t\treturn this.classesService.findOne(id)\n\t}\n\n\t@ApiOperation({\n\t\ttitle: 'Replace one Class 👾'\n\t})\n\t@Put(':id')\n\treplace(@Param('id') id: string, @Body() replaceClassDto: ReplaceClassDto) {\n\t\treturn this.classesService.findOneAndReplace(id, replaceClassDto)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record is executed 👾',\n\t\ttype: Boolean\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Delete one Class 👾'\n\t})\n\t@Delete(':id')\n\tremove(@Param('id') id: string) {\n\t\treturn this.classesService.deleteOne(id)\n\t}\n}\n"
  },
  {
    "path": "src/modules/classes/classes.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ClassesController } from './classes.controller';\nimport { ClassesService } from './classes.service';\n\n@Module({\n  controllers: [ClassesController],\n  providers: [ClassesService]\n})\nexport class ClassesModule {}\n"
  },
  {
    "path": "src/modules/classes/classes.service.ts",
    "content": "import {\n\tInjectable,\n\tNotFoundException,\n\tForbiddenException\n} from '@nestjs/common'\nimport { CreateClassDto } from './dto/create-class.dto'\nimport { ClassEntity } from './entity/class.entity'\nimport { getMongoRepository } from 'typeorm'\nimport { ReplaceClassDto } from './dto/replace-class.dto'\n\nexport type Class = any\n\n@Injectable()\nexport class ClassesService {\n\tasync findAll(): Promise<Class[] | undefined> {\n\t\treturn getMongoRepository(ClassEntity).find()\n\t}\n\n\tasync insert(createClassDto: CreateClassDto): Promise<Class | undefined> {\n\t\tconst { name } = createClassDto\n\t\tconst existedClass = await getMongoRepository(ClassEntity).findOne({\n\t\t\tname\n\t\t})\n\t\tif (existedClass) {\n\t\t\tthrow new ForbiddenException('Name already existed.')\n\t\t}\n\t\tconst newClass = await getMongoRepository(ClassEntity).save(\n\t\t\tnew ClassEntity({\n\t\t\t\t...createClassDto\n\t\t\t})\n\t\t)\n\t\treturn newClass\n\t}\n\tasync findOne(_id: string): Promise<Class | undefined> {\n\t\tconst foundClass = await getMongoRepository(ClassEntity).findOne({ _id })\n\t\tif (!foundClass) {\n\t\t\tthrow new NotFoundException('Class not found.')\n\t\t}\n\t\treturn foundClass\n\t}\n\tasync findOneAndReplace(\n\t\t_id: string,\n\t\treplaceClassDto: ReplaceClassDto\n\t): Promise<Class | undefined> {\n\t\tconst foundClass = await getMongoRepository(ClassEntity).findOne({ _id })\n\t\tif (!foundClass) {\n\t\t\tthrow new NotFoundException('Class not found.')\n\t\t}\n\t\tconst updateClass = await getMongoRepository(ClassEntity).save(\n\t\t\tnew ClassEntity({\n\t\t\t\t...foundClass,\n\t\t\t\t...replaceClassDto\n\t\t\t})\n\t\t)\n\t\treturn updateClass\n\t}\n\tasync deleteOne(_id: string): Promise<boolean | undefined> {\n\t\tconst foundClass = await getMongoRepository(ClassEntity).findOne({ _id })\n\t\tif (!foundClass) {\n\t\t\tthrow new NotFoundException('Class not found.')\n\t\t}\n\t\treturn (await getMongoRepository(ClassEntity).delete(foundClass)) && true\n\t}\n}\n"
  },
  {
    "path": "src/modules/classes/dto/create-class.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class CreateClassDto {\n\t@ApiModelProperty({\n\t\tdefault: '11A1',\n\t\texample: '11A1',\n\t\tdescription: 'The name of the Class'\n\t})\n\t@IsNotEmpty()\n\treadonly name: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'TVK',\n\t\texample: 'TVK',\n\t\tdescription: 'The school of the Class'\n\t})\n\t@IsNotEmpty()\n\treadonly school: string\n}\n"
  },
  {
    "path": "src/modules/classes/dto/replace-class.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class ReplaceClassDto {\n\t@ApiModelProperty({\n\t\tdefault: '11A1',\n\t\texample: '11A1',\n\t\tdescription: 'The name of the Class'\n\t})\n\t@IsNotEmpty()\n\treadonly name: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'TVK',\n\t\texample: 'TVK',\n\t\tdescription: 'The school of the Class'\n\t})\n\t@IsNotEmpty()\n\treadonly school: string\n}\n"
  },
  {
    "path": "src/modules/classes/entity/class.entity.ts",
    "content": "import { Entity, Column, ObjectIdColumn } from 'typeorm'\nimport { ApiModelProperty } from '@nestjs/swagger'\nimport { uuidv4 } from '../../../utils'\n\n@Entity({\n\tname: 'classes',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class ClassEntity {\n\t@ApiModelProperty({ description: 'The _id of the Class' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t@ApiModelProperty({ description: 'The name of the Class' })\n\t@Column()\n\tname: string\n\n\t@ApiModelProperty({ description: 'The school of the Class' })\n\t@Column()\n\tschool: string\n\n\t@ApiModelProperty({ description: 'The createdAt of the Class' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the Class' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<ClassEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/connections/connection.entity.ts",
    "content": "import { Entity, ObjectIdColumn, Column } from 'typeorm'\nimport { uuidv4 } from '../../utils'\n// import { Exclude, plainToClass } from 'class-transformer'\nimport { ApiModelProperty } from '@nestjs/swagger'\n\nimport { ConnectionType } from './enum/connection.enum'\nimport { CreatedByDto } from '../../modules/users/dto/created-by.dto'\n\n@Entity({\n\tname: 'connections',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class ConnectionEntity {\n\t@ApiModelProperty({ description: 'The _id of the Connection' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t@ApiModelProperty({ description: 'The deal of the Connection' })\n\t@Column()\n\tdeal: string\n\n\t@ApiModelProperty({ description: 'The amount of the Connection' })\n\t@Column()\n\tamount: number\n\n\t@ApiModelProperty({ description: 'The connectionType of the Connection' })\n\t@Column()\n\tconnectionType: ConnectionType\n\n\t@ApiModelProperty({ description: 'The createdBy of the Connection' })\n\t@Column()\n\tconnectedBy: CreatedByDto\n\n\t@ApiModelProperty({ description: 'The createdAt of the Connection' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the Connection' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<ConnectionEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.connectionType = ConnectionType.Connected\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/connections/connections.controller.ts",
    "content": "import {\n\tController,\n\tGet,\n\tQuery,\n\tRequest,\n\tUseGuards,\n\tPost,\n\tBody,\n\tParam\n} from '@nestjs/common'\nimport { ConnectionsService, Connection } from './connections.service'\nimport { ConnectionEntity } from './connection.entity'\nimport {\n\tApiResponse,\n\tApiOperation,\n\tApiImplicitQuery,\n\tApiBearerAuth,\n\tApiUseTags\n} from '@nestjs/swagger'\nimport { AuthGuard } from '@nestjs/passport'\nimport { ErrorResponseDto } from '../../modules/users/dto/error-response.dto'\n\n@ApiBearerAuth()\n@UseGuards(AuthGuard('jwt'))\n@ApiResponse({\n\tstatus: 401,\n\tdescription: 'Unauthorized.',\n\ttype: ErrorResponseDto\n})\n@ApiResponse({ status: 403, description: 'Forbidden.', type: ErrorResponseDto })\n@ApiUseTags('connections')\n@Controller('connections')\nexport class ConnectionsController {\n\tconstructor(private readonly connectionsService: ConnectionsService) { }\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [ConnectionEntity]\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Connections 👻'\n\t\t// description: 'Aaa',\n\t\t// operationId: 'aaaa'\n\t})\n\t@Get()\n\t@ApiImplicitQuery({\n\t\tname: 'limit',\n\t\tdescription: 'The maximum number of transactions to return',\n\t\trequired: false,\n\t\ttype: Number\n\t})\n\t@ApiImplicitQuery({\n\t\tname: 'offset',\n\t\tdescription: 'The maximum number of transactions to skip',\n\t\trequired: false,\n\t\ttype: Number\n\t})\n\tfindAll(@Query() query, @Request() req): Promise<Connection[]> {\n\t\treturn this.connectionsService.findAll(query, req)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 201,\n\t\tdescription: 'The record has been successfully created',\n\t\ttype: ConnectionEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one Connection 👻'\n\t})\n\t@Post('/:dealId')\n\tinsert(@Param('dealId') dealId: string, @Request() req): Promise<boolean> {\n\t\treturn this.connectionsService.insert(dealId, req)\n\t}\n}\n"
  },
  {
    "path": "src/modules/connections/connections.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ConnectionsController } from './connections.controller';\nimport { ConnectionsService } from './connections.service';\n\n@Module({\n  controllers: [ConnectionsController],\n  providers: [ConnectionsService]\n})\nexport class ConnectionsModule {}\n"
  },
  {
    "path": "src/modules/connections/connections.service.ts",
    "content": "import { Injectable, ForbiddenException } from '@nestjs/common'\nimport { getMongoRepository } from 'typeorm'\nimport { ConnectionEntity } from './connection.entity'\nimport { UserEntity } from '../../modules/users/user.entity'\nimport { DealEntity } from '../../modules/deals/deal.entity'\n\nexport type Connection = any\n\n@Injectable()\nexport class ConnectionsService {\n\tasync findAll(query: any, req: any): Promise<Connection[]> {\n\t\tconst { offset, limit } = query\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\tconst pipelineArray = []\n\n\t\tif (offset) {\n\t\t\tif (offset < 1) {\n\t\t\t\tthrow new ForbiddenException('The offset must be greater than 0')\n\t\t\t} else {\n\t\t\t\tpipelineArray.push({\n\t\t\t\t\t$skip: +offset\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif (limit) {\n\t\t\tif (limit < 1) {\n\t\t\t\tthrow new ForbiddenException('The limit must be greater than 0')\n\t\t\t} else {\n\t\t\t\tpipelineArray.push({\n\t\t\t\t\t$limit: +limit\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst deal = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'deals',\n\t\t\t\t\tlocalField: 'deal',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'deal'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t'deal.serviceType': 0,\n\t\t\t\t\t'deal.itemType': 0,\n\t\t\t\t\t'deal.description': 0,\n\t\t\t\t\t'deal.shopName': 0,\n\t\t\t\t\t'deal.location': 0,\n\t\t\t\t\t'deal.destination': 0,\n\t\t\t\t\t'deal.payment': 0,\n\t\t\t\t\t'deal.expiredAt': 0,\n\t\t\t\t\t'deal.createdAt': 0,\n\t\t\t\t\t'deal.updatedAt': 0\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: {\n\t\t\t\t\tpath: '$deal',\n\t\t\t\t\tpreserveNullAndEmptyArrays: true\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tconst match = [\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\t$or: [{ connectedBy: _id }, { 'deal.createdBy': _id }]\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tconst dealCreatedBy = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'users',\n\t\t\t\t\tlocalField: 'deal.createdBy',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'deal.createdBy'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t'deal.createdBy.email': 0,\n\t\t\t\t\t'deal.createdBy.password': 0,\n\t\t\t\t\t'deal.createdBy.referralCode': 0,\n\t\t\t\t\t'deal.createdBy.verified': 0,\n\t\t\t\t\t'deal.createdBy.createdAt': 0,\n\t\t\t\t\t'deal.createdBy.updatedAt': 0,\n\t\t\t\t\t'deal.createdBy.phone': 0\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: {\n\t\t\t\t\tpath: '$deal.createdBy',\n\t\t\t\t\tpreserveNullAndEmptyArrays: true\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tconst createdBy = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'users',\n\t\t\t\t\tlocalField: 'connectedBy',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'connectedBy'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t'connectedBy.email': 0,\n\t\t\t\t\t'connectedBy.password': 0,\n\t\t\t\t\t'connectedBy.referralCode': 0,\n\t\t\t\t\t'connectedBy.verified': 0,\n\t\t\t\t\t'connectedBy.createdAt': 0,\n\t\t\t\t\t'connectedBy.updatedAt': 0,\n\t\t\t\t\t'connectedBy.phone': 0\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: {\n\t\t\t\t\tpath: '$connectedBy',\n\t\t\t\t\tpreserveNullAndEmptyArrays: true\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tpipelineArray.push(...deal, ...match, ...dealCreatedBy, ...createdBy)\n\n\t\treturn await getMongoRepository(ConnectionEntity)\n\t\t\t.aggregate(pipelineArray)\n\t\t\t.toArray()\n\t}\n\n\tasync insert(deal: string, req: any): Promise<Connection> {\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\tconst foundDeal = await getMongoRepository(DealEntity).findOne({\n\t\t\t_id: deal\n\t\t})\n\n\t\tif (!foundDeal) {\n\t\t\tthrow new ForbiddenException('Deal not found')\n\t\t}\n\n\t\tconst foundAddress = await getMongoRepository(ConnectionEntity).findOne({\n\t\t\tdeal,\n\t\t\tconnectedBy: _id\n\t\t})\n\n\t\tif (foundAddress) {\n\t\t\tthrow new ForbiddenException('Connection already existed')\n\t\t}\n\n\t\tconst newConnection = await getMongoRepository(ConnectionEntity).save(\n\t\t\tnew ConnectionEntity({ deal, connectedBy: _id })\n\t\t)\n\n\t\tconst connectedBy = await getMongoRepository(UserEntity).findOne({\n\t\t\twhere: {\n\t\t\t\t_id: newConnection.connectedBy\n\t\t\t},\n\t\t\tselect: ['_id', 'name', 'avatar']\n\t\t})\n\n\t\tnewConnection.connectedBy = connectedBy\n\n\t\treturn newConnection\n\t}\n}\n"
  },
  {
    "path": "src/modules/connections/dto/create-connection.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty, IsEnum, IsOptional } from 'class-validator'\n\nimport { ConnectionType } from '../enum/connection.enum'\nimport { Position } from '../../deals/entity/position.entity'\n\nexport class CreateConnectionDto {\n\t@ApiModelProperty({\n\t\tdefault: 'xxxx-xxxx-xxxx-xxxx',\n\t\texample: 'xxxx-xxxx-xxxx-xxxx',\n\t\tdescription: 'The deal of the Connection'\n\t})\n\t@IsOptional()\n\treadonly deal: string\n\n\t@ApiModelProperty({\n\t\tdefault: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\texample: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\tdescription: 'The location of the Connection'\n\t})\n\t@IsNotEmpty()\n\treadonly location: Position\n\n\t@ApiModelProperty({\n\t\tdefault: 69,\n\t\texample: 69,\n\t\tdescription: 'The unitNumber of the Connection'\n\t})\n\t@IsNotEmpty() // 30m 1h 1h30 2h\n\treadonly unitNumber: number\n\n\t@ApiModelProperty({\n\t\tdefault: 'Đối diện BigC',\n\t\texample: 'Đối diện BigC',\n\t\tdescription: 'The remarks of the Connection'\n\t})\n\t@IsOptional()\n\treadonly remarks: string\n}\n"
  },
  {
    "path": "src/modules/connections/enum/connection.enum.ts",
    "content": "export enum ConnectionType {\n\tConnected = 'Connected',\n\tAccepted = 'Accepted',\n\tDeclined = 'Declined',\n\tCompleted = 'Completed'\n}\n"
  },
  {
    "path": "src/modules/deals/deal.entity.ts",
    "content": "import { Entity, ObjectIdColumn, Column } from 'typeorm'\nimport { uuidv4 } from '../../utils'\n// import { Exclude, plainToClass } from 'class-transformer'\nimport { ApiModelProperty } from '@nestjs/swagger'\n\nimport { ItemType, ServiceType, PaymentType, DealType } from './enum/deal.enum'\nimport { Position } from './entity/position.entity'\nimport { UserEntity } from '../users/user.entity'\nimport { CreatedByDto } from '../users/dto/created-by.dto'\n\n@Entity({\n\tname: 'deals',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class DealEntity {\n\t@ApiModelProperty({ description: 'The _id of the Deal' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t@ApiModelProperty({ description: 'The dealType of the Deal' })\n\t@Column()\n\tdealType: DealType\n\n\t@ApiModelProperty({ description: 'The serviceType of the Deal' })\n\t@Column()\n\tserviceType: ServiceType\n\n\t@ApiModelProperty({ description: 'The itemType of the Deal' })\n\t@Column()\n\titemType: ItemType\n\n\t@ApiModelProperty({ description: 'The items of the Deal' })\n\t@Column()\n\titems: string\n\n\t@ApiModelProperty({ description: 'The description of the Deal' })\n\t@Column()\n\tdescription: string\n\n\t@ApiModelProperty({ description: 'The shopName of the Deal' })\n\t@Column()\n\tshopName: string\n\n\t@ApiModelProperty({ description: 'The thumbnail of the Deal' })\n\t@Column()\n\tthumbnail: string\n\n\t@ApiModelProperty({ description: 'The location of the Deal' })\n\t@Column()\n\tlocation: Position\n\n\t@ApiModelProperty({ description: 'The destination of the Deal' })\n\t@Column() // I have no preference auto get location device\n\tdestination: Position\n\n\t@ApiModelProperty({ description: 'The expiredAt of the Deal' })\n\t@Column() // 30m 1h 1h30 2h\n\texpiredAt: number\n\n\t@ApiModelProperty({ description: 'The payment of the Deal' })\n\t@Column()\n\tpayment: PaymentType\n\n\t@ApiModelProperty({ description: 'The createdBy of the Deal' })\n\t@Column()\n\tcreatedBy: CreatedByDto\n\n\t@ApiModelProperty({ description: 'The createdAt of the Deal' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the Deal' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<DealEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/deals/deals.controller.ts",
    "content": "import {\n\tController,\n\tGet,\n\tPost,\n\tBody,\n\tRequest,\n\tUseInterceptors,\n\tUploadedFile,\n\tUseGuards,\n\tParam,\n\tQuery\n} from '@nestjs/common'\nimport { DealsService } from './deals.service'\nimport {\n\tApiOperation,\n\tApiResponse,\n\tApiUseTags,\n\tApiImplicitQuery,\n\tApiConsumes,\n\tApiImplicitFile,\n\tApiBearerAuth\n} from '@nestjs/swagger'\n\nimport { CreateDealDto } from './dto/create-deal.dto'\nimport { FileInterceptor } from '@nestjs/platform-express'\nimport { AuthGuard } from '@nestjs/passport'\nimport { ItemType, ServiceType, DealType } from './enum/deal.enum'\nimport { ErrorResponseDto } from '../../modules/users/dto/error-response.dto'\nimport { DealEntity } from './deal.entity'\nimport { DealResponseDto } from './dto/deal-response.dto'\nimport { Position } from './entity/position.entity'\n\n@ApiResponse({\n\tstatus: 401,\n\tdescription: 'Unauthorized.',\n\ttype: ErrorResponseDto\n})\n@ApiResponse({ status: 403, description: 'Forbidden.', type: ErrorResponseDto })\n@ApiUseTags('deals')\n@Controller('deals')\nexport class DealsController {\n\tconstructor(private readonly dealsService: DealsService) {}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [DealResponseDto]\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Deals 👻'\n\t\t// description: 'Aaa',\n\t\t// operationId: 'aaaa'\n\t})\n\t// @Get(':searchIn')\n\t@Get()\n\t@ApiImplicitQuery({\n\t\tname: 'limit',\n\t\tdescription: 'The maximum number of transactions to return',\n\t\trequired: false,\n\t\ttype: Number\n\t})\n\t@ApiImplicitQuery({\n\t\tname: 'offset',\n\t\tdescription: 'The maximum number of transactions to skip',\n\t\trequired: false,\n\t\ttype: Number\n\t})\n\t@ApiImplicitQuery({\n\t\tname: 'itemType',\n\t\tdescription: 'The itemType of the Deal',\n\t\trequired: false,\n\t\ttype: ItemType,\n\t\tenum: ['None', 'Meal', 'Drinks', 'Desserts', 'Snacks']\n\t})\n\t@ApiImplicitQuery({\n\t\tname: 'serviceType',\n\t\tdescription: 'The serviceType of the Deal',\n\t\trequired: false,\n\t\ttype: ServiceType,\n\t\tenum: [\n\t\t\t'FoodDelivery',\n\t\t\t'Pickup',\n\t\t\t'PharmacyPurchase',\n\t\t\t'Queue',\n\t\t\t'OverseasPurchase',\n\t\t\t'Others'\n\t\t]\n\t})\n\t@ApiImplicitQuery({\n\t\tname: 'dealType',\n\t\tdescription: 'The dealType of the Deal',\n\t\trequired: false,\n\t\ttype: DealType,\n\t\tenum: ['Request', 'Offer']\n\t})\n\tfindAll(\n\t\t// @Param('searchIn') searchIn: string,\n\t\t@Query() query\n\t) {\n\t\t// console.log('sdasd', searchIn)\n\t\treturn this.dealsService.findAll(query)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: DealResponseDto\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one Deal 👻'\n\t})\n\t@Get(':id')\n\tfindOne(@Param('id') id: string) {\n\t\treturn this.dealsService.findOne(id)\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiResponse({\n\t\tstatus: 201,\n\t\tdescription: 'The record has been successfully created.',\n\t\ttype: DealResponseDto\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one Deal 👻'\n\t})\n\t@Post()\n\tinsert(@Body() createDealDto: CreateDealDto, @Request() req) {\n\t\treturn this.dealsService.insert(createDealDto, req)\n\t}\n}\n"
  },
  {
    "path": "src/modules/deals/deals.module.ts",
    "content": "import { Module } from '@nestjs/common'\nimport { DealsController } from './deals.controller'\nimport { DealsService } from './deals.service'\n\n@Module({\n\tcontrollers: [DealsController],\n\tproviders: [DealsService],\n\texports: [DealsService]\n})\nexport class DealsModule {}\n"
  },
  {
    "path": "src/modules/deals/deals.service.ts",
    "content": "import {\n\tInjectable,\n\tNotFoundException,\n\tForbiddenException\n} from '@nestjs/common'\nimport { getMongoRepository } from 'typeorm'\nimport * as geolib from 'geolib'\n\nimport { CreateDealDto } from './dto/create-deal.dto'\nimport { DealEntity } from './deal.entity'\nimport { ServiceType, ItemType } from './enum/deal.enum'\nimport { UserEntity } from '../../modules/users/user.entity'\n\nconst from = {\n\tlatitude: 10.783,\n\tlongitude: 106.692\n}\nconst to = {\n\tlatitude: 10.807,\n\tlongitude: 106.709\n}\n\nconsole.log(\n\t'You are ',\n\tgeolib.getDistance(from, to),\n\t`meters away from ${from}`\n)\n\nexport type Deal = any\n\n@Injectable()\nexport class DealsService {\n\t// TODO:\n\tasync findAll(query): Promise<Deal[] | undefined> {\n\t\t// console.log(query)\n\t\tconst { dealType, serviceType, itemType, offset, limit } = query\n\n\t\tconst pipelineArray = []\n\n\t\tif (offset) {\n\t\t\tif (offset < 1) {\n\t\t\t\tthrow new ForbiddenException('The offset must be greater than 0')\n\t\t\t} else {\n\t\t\t\tpipelineArray.push({\n\t\t\t\t\t$skip: +offset\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif (limit) {\n\t\t\tif (limit < 1) {\n\t\t\t\tthrow new ForbiddenException('The limit must be greater than 0')\n\t\t\t} else {\n\t\t\t\tpipelineArray.push({\n\t\t\t\t\t$limit: +limit\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst connections = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'connections',\n\t\t\t\t\tlocalField: '_id',\n\t\t\t\t\tforeignField: 'dealId',\n\t\t\t\t\tas: 'connections'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tconnections: {\n\t\t\t\t\t\t$size: '$connections'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tconst createdBy = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'users',\n\t\t\t\t\tlocalField: 'createdBy',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'createdBy'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t'createdBy.email': 0,\n\t\t\t\t\t'createdBy.password': 0,\n\t\t\t\t\t'createdBy.referralCode': 0,\n\t\t\t\t\t'createdBy.verified': 0,\n\t\t\t\t\t'createdBy.createdAt': 0,\n\t\t\t\t\t'createdBy.updatedAt': 0,\n\t\t\t\t\t'createdBy.phone': 0\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: {\n\t\t\t\t\tpath: '$createdBy',\n\t\t\t\t\tpreserveNullAndEmptyArrays: true\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tpipelineArray.push(...connections, ...createdBy)\n\n\t\t// console.log(dealType)\n\n\t\tif (dealType) {\n\t\t\tpipelineArray.push({ $match: { dealType } })\n\t\t}\n\n\t\tif (serviceType) {\n\t\t\tpipelineArray.push({ $match: { serviceType } })\n\t\t}\n\n\t\tif (itemType) {\n\t\t\tpipelineArray.push({ $match: { itemType } })\n\t\t}\n\n\t\treturn await getMongoRepository(DealEntity)\n\t\t\t.aggregate(pipelineArray)\n\t\t\t.toArray()\n\t}\n\n\tasync findOne(_id: string): Promise<Deal | undefined> {\n\t\tconst foundDeal = await getMongoRepository(DealEntity).findOne({ _id })\n\n\t\tif (!foundDeal) {\n\t\t\tthrow new NotFoundException('Deal not found')\n\t\t}\n\n\t\treturn foundDeal\n\t}\n\n\t// TODO:\n\tasync insert(createDealDto: CreateDealDto, req: any) {\n\t\t// console.log(createDealDto, file, req.user._id)\n\t\ttry {\n\t\t\tconst { user } = req\n\t\t\tconst { _id } = user\n\t\t\tconst {\n\t\t\t\tdealType,\n\t\t\t\tserviceType,\n\t\t\t\titemType,\n\t\t\t\tlocation,\n\t\t\t\tdestination,\n\t\t\t\tduration,\n\t\t\t\tpayment\n\t\t\t} = createDealDto\n\n\t\t\tlet convertCreateDealDto\n\t\t\tlet newDeal\n\n\t\t\tif (\n\t\t\t\t(createDealDto.serviceType === ServiceType.FoodDelivery &&\n\t\t\t\t\tcreateDealDto.itemType === ItemType.None) ||\n\t\t\t\t(createDealDto.serviceType !== ServiceType.FoodDelivery &&\n\t\t\t\t\tcreateDealDto.itemType !== ItemType.None)\n\t\t\t) {\n\t\t\t\tthrow new ForbiddenException('Service type and Item type is incorrect.')\n\t\t\t}\n\n\t\t\t// if (file && file.size > 1024 * 1024 * 2) {\n\t\t\t// \tthrow new ForbiddenException('The thumbnail is too large to upload')\n\t\t\t// }\n\n\t\t\t// console.log(createDealDto)\n\n\t\t\tif (createDealDto.items === 'Anything') {\n\t\t\t\tconvertCreateDealDto = {\n\t\t\t\t\tdealType,\n\t\t\t\t\tserviceType,\n\t\t\t\t\titemType,\n\t\t\t\t\tlocation: JSON.parse(location.toString()),\n\t\t\t\t\tdestination: JSON.parse(destination.toString()),\n\t\t\t\t\tduration,\n\t\t\t\t\tpayment\n\t\t\t\t}\n\n\t\t\t\tnewDeal = await getMongoRepository(DealEntity).save(\n\t\t\t\t\tnew DealEntity(convertCreateDealDto)\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\t// console.log(file)\n\n\t\t\t\t// if (!file) {\n\t\t\t\t// \tthrow new ForbiddenException('Thumbnail not found.')\n\t\t\t\t// }\n\n\t\t\t\t// const thumbnail = await uploadFile(file)\n\n\t\t\t\tconvertCreateDealDto = {\n\t\t\t\t\t...createDealDto,\n\t\t\t\t\t// thumbnail,\n\t\t\t\t\texpiredAt: +new Date() + 1000 * createDealDto.duration,\n\t\t\t\t\tcreatedBy: _id\n\t\t\t\t}\n\n\t\t\t\tdelete convertCreateDealDto.duration\n\n\t\t\t\tif (createDealDto.serviceType !== ServiceType.FoodDelivery) {\n\t\t\t\t\tdelete convertCreateDealDto.itemType\n\t\t\t\t}\n\n\t\t\t\tnewDeal = await getMongoRepository(DealEntity).save(\n\t\t\t\t\tnew DealEntity(convertCreateDealDto)\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst createdBy = await getMongoRepository(UserEntity).findOne({\n\t\t\t\twhere: {\n\t\t\t\t\t_id: newDeal.createdBy\n\t\t\t\t},\n\t\t\t\tselect: ['_id', 'name', 'avatar']\n\t\t\t})\n\n\t\t\tnewDeal.createdBy = createdBy\n\n\t\t\treturn newDeal\n\t\t} catch (error) {\n\t\t\tthrow new Error(error)\n\t\t}\n\t}\n\n\tasync findByUserId(req: any, query: any): Promise<Deal[] | undefined> {\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\tconst { dealType } = query\n\n\t\tconsole.log(_id)\n\n\t\tconst pipelineArray = []\n\n\t\tif (_id) {\n\t\t\tpipelineArray.push({ $match: { createdBy: _id } })\n\t\t}\n\n\t\tif (dealType) {\n\t\t\tpipelineArray.push({ $match: { dealType } })\n\t\t}\n\n\t\tconst connections = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'connections',\n\t\t\t\t\tlocalField: '_id',\n\t\t\t\t\tforeignField: 'dealId',\n\t\t\t\t\tas: 'connections'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tconnections: {\n\t\t\t\t\t\t$size: '$connections'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tconst createdBy = [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'users',\n\t\t\t\t\tlocalField: 'createdBy',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'createdBy'\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t'createdBy.email': 0,\n\t\t\t\t\t'createdBy.password': 0,\n\t\t\t\t\t'createdBy.referralCode': 0,\n\t\t\t\t\t'createdBy.verified': 0,\n\t\t\t\t\t'createdBy.createdAt': 0,\n\t\t\t\t\t'createdBy.updatedAt': 0,\n\t\t\t\t\t'createdBy.phone': 0\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: {\n\t\t\t\t\tpath: '$createdBy',\n\t\t\t\t\tpreserveNullAndEmptyArrays: true\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\n\t\tpipelineArray.push(...connections, ...createdBy)\n\n\t\treturn await getMongoRepository(DealEntity)\n\t\t\t.aggregate(pipelineArray)\n\t\t\t.toArray()\n\t}\n}\n"
  },
  {
    "path": "src/modules/deals/dto/create-deal.dto.ts",
    "content": "import { ApiModelProperty, ApiModelPropertyOptional } from '@nestjs/swagger'\nimport { IsNotEmpty, IsEnum, IsOptional } from 'class-validator'\n\nimport { ItemType, ServiceType, PaymentType, DealType } from '../enum/deal.enum'\nimport { Position } from '../entity/position.entity'\n\nexport class CreateDealDto {\n\t@ApiModelProperty({\n\t\tenum: ['Request', 'Offer'],\n\t\texample: 'Request',\n\t\tdescription: 'The deal type of the Deal'\n\t})\n\t@IsEnum(DealType)\n\t@IsNotEmpty()\n\treadonly dealType: DealType\n\n\t@ApiModelProperty({\n\t\tenum: [\n\t\t\t'FoodDelivery',\n\t\t\t'Pickup',\n\t\t\t'PharmacyPurchase',\n\t\t\t'Queue',\n\t\t\t'OverseasPurchase',\n\t\t\t'Others'\n\t\t],\n\t\texample: 'FoodDelivery',\n\t\tdescription: 'The service type of the Deal'\n\t})\n\t@IsEnum(ServiceType)\n\t@IsNotEmpty()\n\treadonly serviceType: ServiceType\n\n\t@ApiModelProperty({\n\t\tenum: ['None', 'Meal', 'Drinks', 'Desserts', 'Snacks'],\n\t\texample: 'Meal',\n\t\tdescription: 'The item type of the Deal'\n\t})\n\t@IsEnum(ItemType)\n\t@IsNotEmpty()\n\treadonly itemType: ItemType\n\n\t@ApiModelProperty({\n\t\tdefault: 'Nui xào bò lúc lắc',\n\t\texample: 'Nui xào bò lúc lắc',\n\t\trequired: false,\n\t\tdescription: 'The items of the Deal'\n\t})\n\t@IsOptional()\n\treadonly items: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'Noodle beef cube',\n\t\texample: 'Noodle beef cube',\n\t\trequired: false,\n\t\tdescription: 'The description of the Deal'\n\t})\n\t@IsOptional()\n\treadonly description: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'Tâm Ký',\n\t\texample: 'Tâm Ký',\n\t\trequired: false,\n\t\tdescription: 'The shopName of the Deal'\n\t})\n\t@IsOptional()\n\treadonly shopName: string\n\n\t@ApiModelProperty({\n\t\tdefault: 'https://xxx.xxx',\n\t\texample: 'https://xxx.xxx',\n\t\trequired: false,\n\t\tdescription: 'The thumbnail of the Deal'\n\t})\n\t@IsOptional()\n\tthumbnail: string\n\n\t@ApiModelPropertyOptional({\n\t\tdefault: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\texample: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\tdescription: 'The location of the Deal'\n\t})\n\t@IsNotEmpty()\n\treadonly location: Position\n\n\t@ApiModelPropertyOptional({\n\t\tdefault: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\texample: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\tdescription: 'The destination of the Deal'\n\t})\n\t@IsNotEmpty() // I have no preference auto get location device\n\treadonly destination: Position\n\n\t@ApiModelProperty({\n\t\tdefault: 60 * 60 * 30,\n\t\texample: 60 * 60 * 30,\n\t\tdescription: 'The duration for the expiredAt of the Deal'\n\t})\n\t@IsNotEmpty() // 30m 1h 1h30 2h\n\treadonly duration: number\n\n\t@ApiModelProperty({\n\t\tenum: ['Chewpay', 'Cod'],\n\t\tdescription: 'The payment of the Deal'\n\t})\n\t@IsEnum(PaymentType)\n\t@IsNotEmpty()\n\treadonly payment: PaymentType\n}\n"
  },
  {
    "path": "src/modules/deals/dto/deal-response.dto.ts",
    "content": "import { ApiModelProperty, ApiModelPropertyOptional } from '@nestjs/swagger'\nimport { IsNotEmpty, IsEnum, IsOptional } from 'class-validator'\n\nimport { ItemType, ServiceType, PaymentType, DealType } from '../enum/deal.enum'\nimport { Position } from '../entity/position.entity'\n\nexport class DealResponseDto {\n\t@ApiModelProperty({\n\t\tenum: ['Request', 'Offer'],\n\t\texample: 'Request',\n\t\tdescription: 'The deal type of the Deal'\n\t})\n\t@IsEnum(DealType)\n\t@IsNotEmpty()\n\treadonly dealType: DealType\n\n\t@ApiModelProperty({\n\t\tenum: [\n\t\t\t'FoodDelivery',\n\t\t\t'Pickup',\n\t\t\t'PharmacyPurchase',\n\t\t\t'Queue',\n\t\t\t'OverseasPurchase',\n\t\t\t'Others'\n\t\t],\n\t\texample: 'FoodDelivery',\n\t\tdescription: 'The service type of the Deal'\n\t})\n\t@IsEnum(ServiceType)\n\t@IsNotEmpty()\n\treadonly serviceType: ServiceType\n\n\t@ApiModelProperty({\n\t\tenum: ['None', 'Meal', 'Drinks', 'Desserts', 'Snacks'],\n\t\texample: 'Meal',\n\t\tdescription: 'The item type of the Deal'\n\t})\n\t@IsEnum(ItemType)\n\t@IsNotEmpty()\n\treadonly itemType: ItemType\n\n\t@ApiModelProperty({\n\t\texample: 'Nui xào bò lúc lắc',\n\t\trequired: false,\n\t\tdescription: 'The items of the Deal'\n\t})\n\t@IsOptional()\n\treadonly items: string\n\n\t@ApiModelProperty({\n\t\texample: 'Noodle beef cube',\n\t\trequired: false,\n\t\tdescription: 'The description of the Deal'\n\t})\n\t@IsOptional()\n\treadonly description: string\n\n\t@ApiModelProperty({\n\t\texample: 'Tâm Ký',\n\t\trequired: false,\n\t\tdescription: 'The shopName of the Deal'\n\t})\n\t@IsOptional()\n\treadonly shopName: string\n\n\t@ApiModelProperty({\n\t\texample: 'https://xxx.xxx',\n\t\trequired: false,\n\t\tdescription: 'The thumbnail of the Deal'\n\t})\n\t@IsOptional()\n\tthumbnail: string\n\n\t@ApiModelPropertyOptional({\n\t\texample: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\tdescription: 'The location of the Deal'\n\t})\n\t@IsNotEmpty()\n\treadonly location: Position\n\n\t@ApiModelPropertyOptional({\n\t\texample: {\n\t\t\tlatitude: 10.780230999999999,\n\t\t\tlongitude: 106.6645121\n\t\t},\n\t\tdescription: 'The destination of the Deal'\n\t})\n\t@IsNotEmpty() // I have no preference auto get location device\n\treadonly destination: Position\n\n\t@ApiModelProperty({\n\t\texample: +new Date() + 60 * 60 * 30,\n\t\tdescription: 'The expiredAtt of the Deal'\n\t})\n\t@IsNotEmpty() // 30m 1h 1h30 2h\n\treadonly expiredAt: number\n\n\t@ApiModelProperty({\n\t\tenum: ['Chewpay', 'Cod'],\n\t\tdescription: 'The payment of the Deal'\n\t})\n\t@IsEnum(PaymentType)\n\t@IsNotEmpty()\n\treadonly payment: PaymentType\n\n\t@ApiModelProperty({\n\t\texample: 10,\n\t\tdescription: 'The connections of the Deal'\n\t})\n\t@IsNotEmpty()\n\treadonly connections: number\n\n\t@ApiModelProperty({\n\t\texample: +new Date(),\n\t\tdescription: 'The createdAt of the Deal'\n\t})\n\t@IsNotEmpty()\n\treadonly createdAt: number\n\n\t@ApiModelProperty({\n\t\texample: +new Date(),\n\t\tdescription: 'The updatedAt of the Deal'\n\t})\n\t@IsNotEmpty()\n\treadonly updatedAt: number\n}\n"
  },
  {
    "path": "src/modules/deals/entity/position.entity.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\nimport { Column } from 'typeorm'\n\nexport class Position {\n\t@ApiModelProperty({\n\t\tdefault: 10.780230999999999,\n\t\texample: 10.780230999999999,\n\t\tdescription: 'The latitude of the Position',\n\t\ttype: Number\n\t})\n\t@Column()\n\t@IsNotEmpty()\n\tlatitude: number\n\n\t@ApiModelProperty({\n\t\tdefault: 106.6645121,\n\t\texample: 106.6645121,\n\t\tdescription: 'The longitude of the Position',\n\t\ttype: Number\n\t})\n\t@Column()\n\t@IsNotEmpty()\n\tlongitude: number\n}\n"
  },
  {
    "path": "src/modules/deals/enum/deal.enum.ts",
    "content": "export enum DealType {\n\tRequest = 'Request',\n\tOffer = 'Offer'\n}\n\nexport enum ServiceType {\n\tFoodDelivery = 'FoodDelivery',\n\tPickup = 'Pickup',\n\tPharmacyPurchase = 'PharmacyPurchase',\n\tQueue = 'Queue',\n\tOverseasPurchase = 'OverseasPurchase',\n\tOthers = 'Others'\n}\n\nexport enum ItemType {\n\tNone = 'None',\n\tMeal = 'Meal',\n\tDrinks = 'Drinks',\n\tDesserts = 'Desserts',\n\tSnacks = 'Snacks'\n}\n\nexport enum PaymentType {\n\tChewpay = 'Chewpay',\n\tCod = 'Cod'\n}\n"
  },
  {
    "path": "src/modules/events/events.gateway.ts",
    "content": "import {\n  SubscribeMessage,\n  WebSocketGateway,\n  WebSocketServer,\n  MessageBody,\n  WsResponse,\n} from '@nestjs/websockets';\nimport { Server } from 'socket.io';\nimport { Observable, from } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\n@WebSocketGateway()\nexport class EventsGateway {\n  @WebSocketServer()\n  server: Server;\n\n  @SubscribeMessage('message')\n  handleMessage(client: any, payload: any): string {\n    return 'Hello world!';\n  }\n\n  @SubscribeMessage('events')\n  findAll(@MessageBody() data: any): Observable<WsResponse<number>> {\n    return from([1, 2, 3]).pipe(map(item => ({ event: 'events', data: item })));\n  }\n\n  @SubscribeMessage('identity')\n  async identity(@MessageBody() data: number): Promise<number> {\n    return data;\n  }\n}\n"
  },
  {
    "path": "src/modules/events/events.module.ts",
    "content": "import { Module } from '@nestjs/common';\n\n@Module({})\nexport class EventsModule {}\n"
  },
  {
    "path": "src/modules/students/dto/create-student.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class CreateStudentDto {\n\t@ApiModelProperty({\n\t\tdefault: 'xxxx-xxxx-xxxx-xxxx',\n\t\texample: 'xxxx-xxxx-xxxx-xxxx',\n\t\tdescription: 'The classId of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly classId: string\n\n\t@ApiModelProperty({\n\t\tdefault: 1,\n\t\texample: 1,\n\t\tdescription: 'The stt of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly stt: number\n\n\t@ApiModelProperty({\n\t\tdefault: 'Trần Thế Anh',\n\t\texample: 'Trần Thế Anh',\n\t\tdescription: 'The fullName of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly fullName: string\n}\n"
  },
  {
    "path": "src/modules/students/dto/replace-student.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class ReplaceStudentDto {\n\t@ApiModelProperty({\n\t\tdefault: 'xxxx-xxxx-xxxx-xxxx',\n\t\texample: 'xxxx-xxxx-xxxx-xxxx',\n\t\tdescription: 'The classId of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly classId: string\n\n\t@ApiModelProperty({\n\t\tdefault: 1,\n\t\texample: 1,\n\t\tdescription: 'The stt of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly stt: number\n\n\t@ApiModelProperty({\n\t\tdefault: 'Trần Thế Anh',\n\t\texample: 'Trần Thế Anh',\n\t\tdescription: 'The fullName of the Student'\n\t})\n\t@IsNotEmpty()\n\treadonly fullName: string\n}\n"
  },
  {
    "path": "src/modules/students/entity/student.entity.ts",
    "content": "import { Entity, Column, ObjectIdColumn } from 'typeorm'\nimport { ApiModelProperty } from '@nestjs/swagger'\nimport { uuidv4 } from '../../../utils'\n\n@Entity({\n\tname: 'students',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class StudentEntity {\n\t@ApiModelProperty({ description: 'The _id of the Student' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t@ApiModelProperty({ description: 'The classId of the Student' })\n\t@Column()\n\tclassId: string\n\n\t@ApiModelProperty({ description: 'The stt of the Student' })\n\t@Column()\n\tstt: number\n\n\t@ApiModelProperty({ description: 'The fullname of the Student' })\n\t@Column()\n\tfullName: string\n\n\t@ApiModelProperty({ description: 'The createdAt of the Student' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the Student' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<StudentEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/students/students.controller.ts",
    "content": "import { Controller, Get, Body, Param, Put, Delete, Post } from '@nestjs/common'\nimport { StudentsService } from './students.service'\nimport { ApiResponse, ApiOperation, ApiUseTags } from '@nestjs/swagger'\nimport { StudentEntity } from './entity/student.entity'\nimport { CreateStudentDto } from './dto/create-student.dto'\nimport { ReplaceStudentDto } from './dto/replace-student.dto'\n\n// @ApiBearerAuth()\n// @UseGuards(AuthGuard('jwt'))\n@ApiUseTags('students')\n@Controller('students')\nexport class StudentsController {\n\tconstructor(private readonly studentsService: StudentsService) {}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [StudentEntity]\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Students 👾'\n\t})\n\t@Get()\n\tfindAll() {\n\t\treturn this.studentsService.findAll()\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: StudentEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one Student 👾'\n\t})\n\t@Post()\n\tasync insert(@Body() createStudentDto: CreateStudentDto) {\n\t\tconst newStudent = await this.studentsService.insert(createStudentDto)\n\n\t\treturn newStudent\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: StudentEntity\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one Student 👾'\n\t})\n\t@Get(':id')\n\tfindOne(@Param('id') id: string) {\n\t\treturn this.studentsService.findOne(id)\n\t}\n\n\t@ApiOperation({\n\t\ttitle: 'Replace one Student 👾'\n\t})\n\t@Put(':id')\n\treplace(\n\t\t@Param('id') id: string,\n\t\t@Body() replaceStudentDto: ReplaceStudentDto\n\t) {\n\t\treturn this.studentsService.findOneAndReplace(id, replaceStudentDto)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record is executed 👾',\n\t\ttype: Boolean\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Delete one Student 👾'\n\t})\n\t@Delete(':id')\n\tremove(@Param('id') id: string) {\n\t\treturn this.studentsService.deleteOne(id)\n\t}\n}\n"
  },
  {
    "path": "src/modules/students/students.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { StudentsController } from './students.controller';\nimport { StudentsService } from './students.service';\n\n@Module({\n  controllers: [StudentsController],\n  providers: [StudentsService]\n})\nexport class StudentsModule {}\n"
  },
  {
    "path": "src/modules/students/students.service.ts",
    "content": "import {\n\tInjectable,\n\tNotFoundException,\n\tForbiddenException\n} from '@nestjs/common'\nimport { getMongoRepository } from 'typeorm'\nimport { StudentEntity } from './entity/student.entity'\nimport { ReplaceStudentDto } from './dto/replace-student.dto'\nimport { CreateStudentDto } from './dto/create-student.dto'\nimport { ClassEntity } from '../../modules/classes/entity/class.entity'\n\nexport type Student = any\n\n@Injectable()\nexport class StudentsService {\n\tasync findAll(): Promise<Student[] | undefined> {\n\t\treturn getMongoRepository(StudentEntity).find()\n\t}\n\n\tasync insert(\n\t\tcreateStudentDto: CreateStudentDto\n\t): Promise<Student | undefined> {\n\t\tconst { classId, stt, fullName } = createStudentDto\n\t\tconst foundClass = await getMongoRepository(ClassEntity).findOne({\n\t\t\t_id: classId\n\t\t})\n\t\tif (!foundClass) {\n\t\t\tthrow new NotFoundException('Class not found.')\n\t\t}\n\t\tconst existedStudent = await getMongoRepository(StudentEntity).findOne({\n\t\t\twhere: {\n\t\t\t\t$or: [\n\t\t\t\t\t{ classId, stt },\n\t\t\t\t\t{ classId, fullName }\n\t\t\t\t]\n\t\t\t}\n\t\t})\n\t\tif (existedStudent) {\n\t\t\tthrow new ForbiddenException('Stt or fullName already existed.')\n\t\t}\n\t\tconst newStudent = await getMongoRepository(StudentEntity).save(\n\t\t\tnew StudentEntity({\n\t\t\t\t...createStudentDto\n\t\t\t})\n\t\t)\n\t\treturn newStudent\n\t}\n\tasync findOne(_id: string): Promise<Student | undefined> {\n\t\tconst foundStudent = await getMongoRepository(StudentEntity).findOne({\n\t\t\t_id\n\t\t})\n\t\tif (!foundStudent) {\n\t\t\tthrow new NotFoundException('Student not found.')\n\t\t}\n\t\treturn foundStudent\n\t}\n\tasync findOneAndReplace(\n\t\t_id: string,\n\t\treplaceStudentDto: ReplaceStudentDto\n\t): Promise<Student | undefined> {\n\t\tconst { classId, stt, fullName } = replaceStudentDto\n\t\tconst foundStudent = await getMongoRepository(StudentEntity).findOne({\n\t\t\t_id\n\t\t})\n\t\tif (!foundStudent) {\n\t\t\tthrow new NotFoundException('Student not found.')\n\t\t}\n\t\tconst foundClass = await getMongoRepository(ClassEntity).findOne({\n\t\t\t_id: classId\n\t\t})\n\t\tif (!foundClass) {\n\t\t\tthrow new NotFoundException('Class not found.')\n\t\t}\n\t\tconst existedStudent = await getMongoRepository(StudentEntity).findOne({\n\t\t\twhere: {\n\t\t\t\t$or: [{ stt }, { fullName }]\n\t\t\t}\n\t\t})\n\t\tif (existedStudent) {\n\t\t\tthrow new ForbiddenException('Stt or fullName already existed.')\n\t\t}\n\t\tconst updateStudent = await getMongoRepository(StudentEntity).save(\n\t\t\tnew StudentEntity({\n\t\t\t\t...foundStudent,\n\t\t\t\t...replaceStudentDto\n\t\t\t})\n\t\t)\n\t\treturn updateStudent\n\t}\n\tasync deleteOne(_id: string): Promise<boolean | undefined> {\n\t\tconst foundStudent = await getMongoRepository(StudentEntity).findOne({\n\t\t\t_id\n\t\t})\n\t\tif (!foundStudent) {\n\t\t\tthrow new NotFoundException('Student not found.')\n\t\t}\n\t\treturn (\n\t\t\t(await getMongoRepository(StudentEntity).delete(foundStudent)) && true\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "src/modules/users/dto/create-user.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty, IsEmail, Length } from 'class-validator'\n\nexport class CreateUserDto {\n\t@ApiModelProperty({\n\t\texample: 'trinhchin',\n\t\tdescription: 'The name of the User'\n\t})\n\t@Length(5, 20)\n\t@IsNotEmpty()\n\treadonly name: string\n\n\t@ApiModelProperty({\n\t\texample: 'trinhchin.innos@gmail.com',\n\t\tdescription: 'The email of the User'\n\t})\n\t@IsEmail()\n\t@IsNotEmpty()\n\treadonly email: string\n\n\t@ApiModelProperty({\n\t\texample: '0',\n\t\tdescription: 'The password of the User'\n\t})\n\t@IsNotEmpty()\n\treadonly password: string\n\n\t@ApiModelProperty({\n\t\texample: '12341234',\n\t\tdescription: 'The referralCode of the User'\n\t})\n\t@Length(8, 8)\n\t@IsNotEmpty()\n\treadonly referralCode: string\n}\n"
  },
  {
    "path": "src/modules/users/dto/created-by.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class CreatedByDto {\n  @ApiModelProperty({\n    example: 'xxxx-xxxx-xxxx-xxxx',\n    description: 'The _id of the CreatedBy'\n  })\n  @IsNotEmpty()\n  readonly _id: string\n\n  @ApiModelProperty({\n    example: 'xxxxxxxxxx',\n    description: 'The name of the CreatedBy'\n  })\n  @IsNotEmpty()\n  readonly name: string\n\n  @ApiModelProperty({\n    example: 'https://xxx.xxx',\n    description: 'The avatar of the CreatedBy'\n  })\n  @IsNotEmpty()\n  readonly avatar: string\n}\n"
  },
  {
    "path": "src/modules/users/dto/error-response.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class ErrorResponseDto {\n  @ApiModelProperty({\n    example: '40x',\n    description: 'The statusCode of the ErrorResponse'\n  })\n  @IsNotEmpty()\n  readonly statusCode: string\n\n  @ApiModelProperty({\n    example: 'xxxxxxxxxx',\n    description: 'The message of the ErrorResponse'\n  })\n  @IsNotEmpty()\n  readonly message: string\n\n  @ApiModelProperty({\n    example: '2019-11-28T03:08:10.980Z',\n    description: 'The timestamp of the ErrorResponse'\n  })\n  @IsNotEmpty()\n  readonly timestamp: string\n\n  @ApiModelProperty({\n    example: '/v1',\n    description: 'The path of the ErrorResponse'\n  })\n  @IsNotEmpty()\n  readonly path: string\n}\n"
  },
  {
    "path": "src/modules/users/dto/login-response.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\nimport { UserEntity } from '../user.entity'\n\nexport class LoginResponseDto {\n\t@ApiModelProperty({\n\t\texample: UserEntity,\n\t\tdescription: 'The user of the LoginResponse'\n\t})\n\t@IsNotEmpty()\n\treadonly user: UserEntity\n\n\t@ApiModelProperty({\n\t\texample: 'xxxxxxxxxx',\n\t\tdescription: 'The accessToken of the LoginResponse'\n\t})\n\t@IsNotEmpty()\n\treadonly accessToken: string\n\n\t@ApiModelProperty({\n\t\texample: 60 * 60 * 24 * 30,\n\t\tdescription: 'The expiresIn of the LoginResponse'\n\t})\n\t@IsNotEmpty()\n\treadonly expiresIn: number\n}\n"
  },
  {
    "path": "src/modules/users/dto/login-user.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty, IsEmail } from 'class-validator'\n\nexport class LoginUserDto {\n\t@ApiModelProperty({\n\t\tdefault: 'trinhchin.innos@gmail.com',\n\t\texample: 'trinhchin.innos@gmail.com',\n\t\tdescription: 'The email of the User'\n\t})\n\t@IsEmail()\n\t@IsNotEmpty()\n\treadonly email: string\n\n\t@ApiModelProperty({\n\t\tdefault: '0',\n\t\texample: '0',\n\t\tdescription: 'The password of the User'\n\t})\n\t@IsNotEmpty()\n\treadonly password: string\n}\n"
  },
  {
    "path": "src/modules/users/dto/otp-response.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class OtpResponseDto {\n\t@ApiModelProperty({\n\t\tdefault: 678900,\n\t\texample: 678900,\n\t\tdescription: 'The otp of the OtpResponseDto'\n\t})\n\t@IsNotEmpty()\n\treadonly otp: number\n\n\t@ApiModelProperty({\n\t\tdefault: '60s',\n\t\texample: '60s',\n\t\tdescription: 'The remaining of the OtpResponseDto'\n\t})\n\t@IsNotEmpty()\n\treadonly remaining: string\n}\n"
  },
  {
    "path": "src/modules/users/dto/replace-user.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger';\nimport { IsNotEmpty, Length } from 'class-validator';\n\nexport class ReplaceUserDto {\n  @ApiModelProperty({ description: 'The name of the User' })\n  @Length(5, 20)\n  @IsNotEmpty()\n  readonly name: string;\n\n  @ApiModelProperty({ description: 'The referralCode of the User' })\n  @Length(8, 8)\n  @IsNotEmpty()\n  readonly referralCode: string;\n}\n"
  },
  {
    "path": "src/modules/users/dto/update-user.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger';\nimport { Length, IsOptional } from 'class-validator';\n\nexport class UpdateUserDto {\n  @ApiModelProperty({\n    required: false,\n    description: 'The name of the User',\n  })\n  @Length(5, 20)\n  @IsOptional()\n  readonly name: string;\n\n  @ApiModelProperty({\n    required: false,\n    description: 'The referralCode of the User',\n  })\n  @Length(8, 8)\n  @IsOptional()\n  readonly referralCode: string;\n}\n"
  },
  {
    "path": "src/modules/users/dto/upload-response.dto.ts",
    "content": "import { ApiModelProperty } from '@nestjs/swagger'\nimport { IsNotEmpty } from 'class-validator'\n\nexport class UploadResponseDto {\n  @ApiModelProperty({\n    example: 'https://xxx.xxx',\n    description: 'The path of the UploadResponse'\n  })\n  @IsNotEmpty()\n  readonly url: string\n}\n"
  },
  {
    "path": "src/modules/users/index.ts",
    "content": "import * as speakeasy from 'speakeasy'\n\nconst token = speakeasy.totp({\n\tsecret: '123456',\n\tencoding: 'base32'\n})\n\nconst tokenValidates = speakeasy.totp.verify({\n\tsecret: '123456',\n\tencoding: 'base32',\n\ttoken,\n\twindow: 0\n})\n\nconsole.log(tokenValidates)\n"
  },
  {
    "path": "src/modules/users/user.entity.ts",
    "content": "import { Entity, ObjectIdColumn, Column } from 'typeorm'\nimport { uuidv4 } from '../../utils'\nimport { Exclude, plainToClass } from 'class-transformer'\nimport { ApiModelProperty } from '@nestjs/swagger'\nimport { Position } from '../../modules/deals/entity/position.entity'\n\n@Entity({\n\tname: 'users',\n\torderBy: {\n\t\tcreatedAt: 'ASC'\n\t}\n})\nexport class UserEntity {\n\t@ApiModelProperty({ description: 'The _id of the User' })\n\t@ObjectIdColumn()\n\t_id: string\n\n\t// basic\n\n\t@ApiModelProperty({ description: 'The name of the User' })\n\t@Column()\n\tname: string\n\n\t@ApiModelProperty({ description: 'The email of the User' })\n\t@Column()\n\temail: string\n\n\t@ApiModelProperty({ description: 'The password of the User' })\n\t@Exclude()\n\t@Column()\n\tpassword: string\n\n\t@ApiModelProperty({ description: 'The referralCode of the User' })\n\t@Column()\n\treferralCode: string\n\n\t@ApiModelProperty({ description: 'The search location of the User' })\n\t@Column()\n\tsearchIn: Position\n\n\t// @Column()\n\t// countryCode: string; // Vietname +84\n\t// @Column()\n\t// phone: string; // 0704498756\n\t// @Column()\n\t// verified: boolean; // false\n\t// @Column()\n\t// authyId: string; // null\n\n\t@ApiModelProperty({ description: 'The avatar of the User' })\n\t@Column()\n\tavatar: string\n\n\t@ApiModelProperty({ description: 'The phone of the User' })\n\t@Column()\n\tphone: string\n\n\t@ApiModelProperty({ description: 'The verified of the User' })\n\t@Column()\n\tverified: boolean\n\n\t@ApiModelProperty({ description: 'The createdAt of the User' })\n\t@Column()\n\tcreatedAt: number\n\t@ApiModelProperty({ description: 'The updatedAt of the User' })\n\t@Column()\n\tupdatedAt: number\n\n\tconstructor(partial: Partial<UserEntity>) {\n\t\tif (partial) {\n\t\t\tObject.assign(this, partial)\n\t\t\tthis._id = this._id || uuidv4()\n\t\t\tthis.avatar =\n\t\t\t\tthis.avatar ||\n\t\t\t\t'https://res.cloudinary.com/chnirt/image/upload/v1573662028/rest/2019-11-13T16:20:22.699Z.png'\n\t\t\tthis.verified = this.verified || false\n\t\t\tthis.createdAt = this.createdAt || +new Date()\n\t\t\tthis.updatedAt = +new Date()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/modules/users/users.controller.ts",
    "content": "import {\n\tController,\n\tUseGuards,\n\tPost,\n\tGet,\n\tParam,\n\tClassSerializerInterceptor,\n\tUseInterceptors,\n\tPut,\n\tPatch,\n\tBody,\n\tDelete,\n\tUploadedFile,\n\tRequest\n} from '@nestjs/common'\nimport { AuthGuard } from '@nestjs/passport'\nimport {\n\tApiBearerAuth,\n\tApiUseTags,\n\tApiOperation,\n\tApiResponse,\n\tApiConsumes,\n\tApiImplicitFile\n} from '@nestjs/swagger'\nimport { FileInterceptor } from '@nestjs/platform-express'\nimport * as jwt from 'jsonwebtoken'\n\nimport { UserEntity } from './user.entity'\nimport { CreateUserDto } from './dto/create-user.dto'\nimport { UsersService } from './users.service'\nimport { UpdateUserDto } from './dto/update-user.dto'\nimport { ReplaceUserDto } from './dto/replace-user.dto'\nimport { ErrorResponseDto } from './dto/error-response.dto'\nimport { LoginResponseDto } from './dto/login-response.dto'\nimport { OtpResponseDto } from './dto/otp-response.dto'\nimport { AuthService } from '../../auth/auth.service'\n\n@ApiResponse({\n\tstatus: 401,\n\tdescription: 'Unauthorized.',\n\ttype: ErrorResponseDto\n})\n@ApiResponse({ status: 403, description: 'Forbidden.', type: ErrorResponseDto })\n@UseInterceptors(ClassSerializerInterceptor)\n@ApiUseTags('users')\n@Controller('users')\nexport class UsersController {\n\tconstructor(\n\t\tprivate readonly authService: AuthService,\n\t\tprivate readonly userService: UsersService\n\t) {}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found records',\n\t\ttype: [UserEntity]\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Retrieve many Users 👻'\n\t})\n\t@Get()\n\tfindAll() {\n\t\treturn this.userService.findAll()\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: LoginResponseDto\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Create one User 👻'\n\t})\n\t@Post()\n\tasync insert(@Body() createUserDto: CreateUserDto) {\n\t\tconst newUser = await this.userService.insert(createUserDto)\n\n\t\tconst loginResponseDto = await this.authService.login(newUser)\n\n\t\treturn loginResponseDto\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record',\n\t\ttype: UserEntity\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Retrieve one User 👻'\n\t})\n\t@Get(':id')\n\tfindOne(@Param('id') id: string) {\n\t\treturn this.userService.findOne(id)\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Update one User 👻'\n\t})\n\t@Patch(':id')\n\tupdate(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {\n\t\treturn this.userService.findOneAndUpdate(id, updateUserDto)\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Replace one User 👻'\n\t})\n\t@Put(':id')\n\treplace(@Param('id') id: string, @Body() replaceUserDto: ReplaceUserDto) {\n\t\treturn this.userService.findOneAndReplace(id, replaceUserDto)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record is executed 👻',\n\t\ttype: Boolean\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Delete one User 👻'\n\t})\n\t@Delete(':id')\n\tremove(@Param('id') id: string) {\n\t\treturn this.userService.deleteOne(id)\n\t}\n\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record is executed',\n\t\ttype: Boolean\n\t})\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiOperation({\n\t\ttitle: 'Update one Avatar for current User 👻'\n\t})\n\t@Post('avatar')\n\t@ApiConsumes('multipart/form-data')\n\t@ApiImplicitFile({\n\t\tname: 'avatar',\n\t\trequired: true,\n\t\tdescription: 'Send one file'\n\t})\n\t@UseInterceptors(FileInterceptor('avatar'))\n\tupdateAvatar(@Request() req, @UploadedFile() file) {\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\treturn this.userService.updateAvatar(_id, file)\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiResponse({\n\t\tstatus: 201,\n\t\tdescription: 'The found record is executed',\n\t\ttype: OtpResponseDto\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Otp one User 👻'\n\t})\n\t@Post('/otp/:phone')\n\totp1(@Request() req, @Param('phone') phone: string) {\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\treturn this.userService.otp(_id, phone)\n\t}\n\n\t@ApiBearerAuth()\n\t@UseGuards(AuthGuard('jwt'))\n\t@ApiResponse({\n\t\tstatus: 200,\n\t\tdescription: 'The found record is executed',\n\t\ttype: LoginResponseDto\n\t})\n\t@ApiOperation({\n\t\ttitle: 'Verify one User 👻'\n\t})\n\t@Post('/verify/:otp')\n\tasync verify(\n\t\t@Request() req,\n\t\t@Param('otp') otp: string\n\t): Promise<LoginResponseDto | undefined> {\n\t\tconst { user } = req\n\t\tconst { _id } = user\n\n\t\tconst updateUser = await this.userService.verify(_id, otp)\n\n\t\tconst loginResponseDto = await this.authService.login(updateUser)\n\n\t\treturn loginResponseDto\n\t}\n}\n"
  },
  {
    "path": "src/modules/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common'\nimport { UsersService } from './users.service'\nimport { UsersController } from './users.controller'\nimport { AuthModule } from '../../auth/auth.module'\n\n@Module({\n\timports: [AuthModule],\n\tcontrollers: [UsersController],\n\tproviders: [UsersService],\n\texports: [UsersService]\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "src/modules/users/users.service.ts",
    "content": "import {\n\tInjectable,\n\tForbiddenException,\n\tNotFoundException\n} from '@nestjs/common'\nimport { CreateUserDto } from './dto/create-user.dto'\nimport { getMongoRepository } from 'typeorm'\nimport * as speakeasy from 'speakeasy'\nimport { Validator } from 'class-validator'\n\nimport { UserEntity } from './user.entity'\nimport { hashPassword } from '../../utils'\nimport { UpdateUserDto } from './dto/update-user.dto'\nimport { ReplaceUserDto } from './dto/replace-user.dto'\n\nimport { uploadFile } from '../../shared'\n\nimport { SPEAKEASY_SECRET, SPEAKEASY_STEP } from '../../environments'\nimport { OtpResponseDto } from './dto/otp-response.dto'\n\nconst validator = new Validator()\nexport type User = any\n\n@Injectable()\nexport class UsersService {\n\tasync insert(createUserDto: CreateUserDto): Promise<User | undefined> {\n\t\tconst { email } = createUserDto\n\n\t\tconst existedUser = await getMongoRepository(UserEntity).findOne({ email })\n\n\t\tif (existedUser) {\n\t\t\tthrow new ForbiddenException('Email already existed.')\n\t\t}\n\n\t\tconst newUser = await getMongoRepository(UserEntity).save(\n\t\t\tnew UserEntity({\n\t\t\t\t...createUserDto,\n\t\t\t\tpassword: await hashPassword(createUserDto.password)\n\t\t\t})\n\t\t)\n\n\t\treturn newUser\n\t}\n\n\tasync findAll(): Promise<User[] | undefined> {\n\t\treturn getMongoRepository(UserEntity).find()\n\t}\n\n\tasync findOne(_id: string): Promise<User | undefined> {\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({ _id })\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\treturn foundUser\n\t}\n\n\tasync findOneAndReplace(\n\t\t_id: string,\n\t\treplaceUserDto: ReplaceUserDto\n\t): Promise<User | undefined> {\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({ _id })\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\tconst updateUser = await getMongoRepository(UserEntity).save(\n\t\t\tnew UserEntity({\n\t\t\t\t...foundUser,\n\t\t\t\t...replaceUserDto\n\t\t\t})\n\t\t)\n\n\t\treturn updateUser\n\t}\n\n\tasync findOneAndUpdate(\n\t\t_id: string,\n\t\tupdateUserDto: UpdateUserDto\n\t): Promise<User | undefined> {\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({ _id })\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\tconst updateUser = await getMongoRepository(UserEntity).save(\n\t\t\tnew UserEntity({\n\t\t\t\t...foundUser,\n\t\t\t\t...updateUserDto\n\t\t\t})\n\t\t)\n\n\t\treturn updateUser\n\t}\n\n\tasync deleteOne(_id: string): Promise<boolean | undefined> {\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({ _id })\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\treturn (await getMongoRepository(UserEntity).delete(foundUser))\n\t\t\t? true\n\t\t\t: false\n\t}\n\n\tasync findOneWithEmail(email: string): Promise<User | undefined> {\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({ email })\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\treturn foundUser\n\t}\n\n\tasync updateAvatar(_id: string, file: any): Promise<boolean | undefined> {\n\t\t// console.log(_id, file)\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({ _id })\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\tfoundUser.avatar = await uploadFile(file)\n\n\t\tconst updateUser = await getMongoRepository(UserEntity).save(foundUser)\n\n\t\treturn updateUser ? true : false\n\t}\n\n\tasync otp(_id: string, phone: string): Promise<OtpResponseDto | undefined> {\n\t\tvalidator.isMobilePhone(phone, 'en-SG')\n\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({\n\t\t\twhere: {\n\t\t\t\t_id,\n\t\t\t\tverified: false\n\t\t\t}\n\t\t})\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\tconst token = await speakeasy.totp({\n\t\t\tsecret: SPEAKEASY_SECRET!,\n\t\t\tencoding: 'base32',\n\t\t\t// digits: SPEAKEASY_DIGITS!\n\t\t\tstep: SPEAKEASY_STEP! // 30s\n\t\t\t// window: 1 // pre 30s cur 30s nxt 30s\n\t\t})\n\n\t\tconst remaining =\n\t\t\tSPEAKEASY_STEP - Math.floor((+new Date() / 1000.0) % SPEAKEASY_STEP) + 's'\n\n\t\tfoundUser.phone = phone\n\n\t\tawait getMongoRepository(UserEntity).save(foundUser)\n\n\t\treturn {\n\t\t\totp: +token,\n\t\t\tremaining\n\t\t}\n\t}\n\n\tasync verify(_id: string, otp: string) {\n\t\tconst foundUser = await getMongoRepository(UserEntity).findOne({\n\t\t\twhere: {\n\t\t\t\t_id,\n\t\t\t\tverified: false\n\t\t\t}\n\t\t})\n\n\t\tif (!foundUser) {\n\t\t\tthrow new NotFoundException('User not found.')\n\t\t}\n\n\t\t// console.log(otp)\n\n\t\tconst verified = await speakeasy.totp.verify({\n\t\t\tsecret: SPEAKEASY_SECRET!,\n\t\t\tencoding: 'base32',\n\t\t\ttoken: otp,\n\t\t\tstep: SPEAKEASY_STEP!, // 30s\n\t\t\twindow: 1\n\t\t})\n\n\t\t// console.log(verified)\n\n\t\tif (verified) {\n\t\t\tfoundUser.verified = true\n\n\t\t\treturn await getMongoRepository(UserEntity).save(foundUser)\n\t\t}\n\n\t\tthrow new ForbiddenException('Otp is incorrect.')\n\t}\n}\n"
  },
  {
    "path": "src/shared/index.ts",
    "content": "export * from './upload'\n"
  },
  {
    "path": "src/shared/upload/index.ts",
    "content": "import * as cloudinary from 'cloudinary'\n\nimport { CLOUD_NAME, API_KEY, API_SECRET } from '../../environments'\n\n/**\n * Returns image url by upload file.\n *\n * @remarks\n * This method is part of the {@link shared/upload}.\n *\n * @param createReadStream - 1st input number\n * @returns The string mean of `createReadStream`\n *\n * @beta\n */\nexport const uploadFile = async (file: any): Promise<string> => {\n\tcloudinary.config({\n\t\tcloud_name: CLOUD_NAME!,\n\t\tapi_key: API_KEY!,\n\t\tapi_secret: API_SECRET!\n\t})\n\n\tconst uniqueFilename = new Date().toISOString()\n\n\tconst result = await new Promise(async (resolve, reject) => {\n\t\tcloudinary.v2.uploader\n\t\t\t.upload_stream(\n\t\t\t\t{\n\t\t\t\t\tfolder: 'rest',\n\t\t\t\t\tpublic_id: uniqueFilename,\n\t\t\t\t\ttags: 'rest'\n\t\t\t\t}, // directory and tags are optional\n\t\t\t\t(err, image) => {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err)\n\t\t\t\t\t}\n\t\t\t\t\tresolve(image)\n\t\t\t\t}\n\t\t\t)\n\t\t\t.end(file.buffer)\n\t})\n\n\t// tslint:disable-next-line:no-string-literal\n\treturn result['secure_url']\n}\n"
  },
  {
    "path": "src/terminus-options.service.ts",
    "content": "import {\n  TerminusEndpoint,\n  TerminusOptionsFactory,\n  DNSHealthIndicator,\n  TerminusModuleOptions,\n} from '@nestjs/terminus';\nimport { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class TerminusOptionsService implements TerminusOptionsFactory {\n  constructor(private readonly dns: DNSHealthIndicator) {}\n\n  createTerminusOptions(): TerminusModuleOptions {\n    const healthEndpoint: TerminusEndpoint = {\n      url: '/health',\n      healthIndicators: [\n        async () => this.dns.pingCheck('google', 'https://google.com'),\n      ],\n    };\n    return {\n      endpoints: [healthEndpoint],\n    };\n  }\n}\n"
  },
  {
    "path": "src/utils/index.ts",
    "content": "export * from './password';\nexport * from './uuid';\n"
  },
  {
    "path": "src/utils/password/index.ts",
    "content": "import { hash, compare } from 'bcrypt';\n\nimport { SALT } from '../../environments';\n\n/**\n * Returns hashed password by hash password.\n *\n * @remarks\n * This method is part of the {@link utils/password}.\n *\n * @param password - 1st input number\n * @returns The hashed password mean of `password`\n *\n * @beta\n */\nexport const hashPassword = async (password: string): Promise<string> => {\n  return await hash(password, SALT);\n};\n\n/**\n * Returns boolean by compare password.\n *\n * @remarks\n * This method is part of the {@link utils/password}.\n *\n * @param password - 1st input number\n * @param hash - The second input number\n * @returns The boolean mean of `password` and `hash`\n *\n * @beta\n */\nexport const comparePassword = async (\n  password: string,\n  hash: string,\n): Promise<boolean> => {\n  return await compare(password, hash);\n};\n"
  },
  {
    "path": "src/utils/uuid/index.ts",
    "content": "/**\n * Returns string by uuidv4.\n *\n * @remarks\n * This method is part of the {@link utils/uuid}.\n *\n * @returns The string\n *\n * @beta\n */\nexport const uuidv4 = () => {\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n    const r = (Math.random() * 16) | 0;\n    const v = c === 'x' ? r : (r & 0x3) | 0x8;\n    return v.toString(16);\n  });\n};\n\n/**\n * Returns string by generateUID.\n *\n * @remarks\n * This method is part of the {@link utils/uuid}.\n *\n * @returns The string\n *\n * @beta\n */\nexport const generateUID = () => {\n  // I generate the UID from two parts here\n  // to ensure the random number provide enough bits.\n  const firstPart = (Math.random() * 46656) | 0;\n  const secondPart = (Math.random() * 46656) | 0;\n  const newFirstPart = ('000' + firstPart.toString(36)).slice(-3);\n  const newSecondPart = ('000' + secondPart.toString(36)).slice(-3);\n  return newFirstPart + newSecondPart;\n};\n\n// console.log(uuidv4())\n// console.log(generateUID())\n"
  },
  {
    "path": "ssl/ca_bundle.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nZ8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\na6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\nAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\nCCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\nbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\nc3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\nVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\nARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\nMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\nY3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\nAAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\nuM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\nwApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\nX4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\nPfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----"
  },
  {
    "path": "ssl/certificate.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFjDCCBHSgAwIBAgISAxzigJJ7e4L0h878QlVRGOH6MA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTExMTAwMzM2MDFaFw0y\nMDAyMDgwMzM2MDFaMDUxMzAxBgNVBAMTKm5lc3Rqcy1yZXN0ZnVsLWJlc3QtcHJh\nY3RpY2UuaGVyb2t1YXBwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBAKOMUnWgi/uPB3Kr8Ay51rzVES/Tr8EaebjRKSSOGw8h4ZNaPAeDg7ZH1PvV\nm5JexIJ4EAfd2jSV8GZZl7xBmG1GWgyjnWnQTwJ643F2EK2UNC5KLaCvMyeDkNTl\nJW2Ur/0nCR8oUEBAx9QsbIJ0HhWofDRTOttOcrfsjnqtnWJl20PNeDS7NGjewUhe\n+Yk1Z705mGZezxeU3dNmQnpGEFxo6p5Y/M8maD04LxZUUKxReeLPDHGYuNkY+klq\nY8FReaXJTTFH92XIOS4ECwvLk6XgCwiX+xCH3gerdBIiuP6LTA2RNf0lhs24duhI\neGHwJeYSvmVfUXS3V11OyDcv7qUCAwEAAaOCAn8wggJ7MA4GA1UdDwEB/wQEAwIF\noDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd\nBgNVHQ4EFgQUSk/oIsx9g6CBliPWqcsK52nF6CUwHwYDVR0jBBgwFoAUqEpqYwR9\n3brm0Tm3pkVl7/Oo7KEwbwYIKwYBBQUHAQEEYzBhMC4GCCsGAQUFBzABhiJodHRw\nOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3JnMC8GCCsGAQUFBzAChiNodHRw\nOi8vY2VydC5pbnQteDMubGV0c2VuY3J5cHQub3JnLzA1BgNVHREELjAsgipuZXN0\nanMtcmVzdGZ1bC1iZXN0LXByYWN0aWNlLmhlcm9rdWFwcC5jb20wTAYDVR0gBEUw\nQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDov\nL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgCy\nHgXMi6LNiiBOh2b5K7mKJSBna9r6cOeySVMt74uQXgAAAW5TmOwuAAAEAwBHMEUC\nICFD2zRfc3lLDyFv8ziOkIhGAqm3m0OfsLUfEfBsOFD3AiEA1RW78rTM9GSCvcfz\nng7JtgocQGoCwRtHUOwueNxRlGUAdgBvU3asMfAxGdiZAKRRFf93FRwR2QLBACkG\njbIImjfZEwAAAW5TmOxgAAAEAwBHMEUCIQDG6XXZbQvg+OKdAJ6F5bEtRvdH2ZOO\nMFrErGSfbA5QdgIgFzhbbaFKGwk4G+kO2+mJYo7clgLR+WIuW/C8fQSIOI8wDQYJ\nKoZIhvcNAQELBQADggEBACksWIQEdpa9cuDVw/gsOqnbNirDZCJI3JqM58zWRxSl\nkOlBmsmQRzHeveR6CSu/GOiR4HeFF+To0zjBX8U14ufwNOj5eS0jVkwEgN5weWbh\ninbWc1PsFuwzISYrG0ssDXP2ty+8Dpg3WjfZg9RE36PsQuH3rQl1A6i0uz9vVASu\nbccgjJWVvsJF72DPNzOAD9T8wdcXvKrVb/GU19D1s5NHDUcogBqRSPrjUuLiW8BN\np6F8UMV1iXbPDSVdI71sDhpaBt7EP6jwBgfDnGuNLrUDBg7WsmtQrBdbg5oRhTw0\n5FiaP0roSCHV9gpH3R+VgLmLbRa8o6ssWYlS8vEoA7A=\n-----END CERTIFICATE-----"
  },
  {
    "path": "ssl/private.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjjFJ1oIv7jwdy\nq/AMuda81REv06/BGnm40SkkjhsPIeGTWjwHg4O2R9T71ZuSXsSCeBAH3do0lfBm\nWZe8QZhtRloMo51p0E8CeuNxdhCtlDQuSi2grzMng5DU5SVtlK/9JwkfKFBAQMfU\nLGyCdB4VqHw0UzrbTnK37I56rZ1iZdtDzXg0uzRo3sFIXvmJNWe9OZhmXs8XlN3T\nZkJ6RhBcaOqeWPzPJmg9OC8WVFCsUXnizwxxmLjZGPpJamPBUXmlyU0xR/dlyDku\nBAsLy5Ol4AsIl/sQh94Hq3QSIrj+i0wNkTX9JYbNuHboSHhh8CXmEr5lX1F0t1dd\nTsg3L+6lAgMBAAECggEAB+R4Vj+D1y/1JrjawhfLH8cTJ+u0n5es0sPFPdkIapfd\nUERv1oJSPjRZODimuU7kIiezyQK7yliHXBPBbs77kXUZA2Mh8D6ikXa8uHeqIQug\njltQuGBmvObB0S79uhFi13n6xrYl/p53BkDekQJphpdgPGYygO2C5mf+uDeIpibl\nu4TwRZmELPjY7ZPJlq0Sv+G93FDbF5yLa4/sQwrjfPFBq0XDEmN4r2kcCGZwpq0L\nBIw4Jl+XnNU/HHPvBShe5Nx+URgQuGkWCHmpChYRAfXjLZk65ZomcfFVgTgxg786\ngmZZdpHr129F9BAwDcp5QMfl1zs4g4qlN8c9ttxgQQKBgQDcBhGdvt4aNNFbxVWw\npr7hwmryYYzR64Wnp3IjaIMpCabOzsIVoS/8kq60l7c9aag5KgJoqLNZfUeue38H\noDXnAkflXveI41VbpwleAAb3+R1d6jlIJjJaJtAX1byivLkqXl4qjoau+040myKj\n7POhUgNjcGEtyClvNgkAY4nfPwKBgQC+SkC6F9LQSeDinhFWty9kjaeL15hnjJMR\nQJ7fzPkziFZLlEa9ggv5CBJD+k/uXguLRxt6IaHCE4uwQPALGL0iMC6xaAfCOLJz\nojOJxlYOuLjDSPeylAQ+QjlM62zF23JvQlc1/QZBsgBFfCNWkDHpHhyiQi6Cv7mp\nyr42fxTdGwKBgCi+VvTHK4nezgYYfM3BkwdrYTKRLeqRmqZ5M4GrEN7AksspLnei\n6afz4bY/ggc1UZmEVf3bf5rKwENnSxa2bETi/z1SYLRQpLXcMLffeWriDrYdcY4S\nxLA9D7vaMJxSJlfaMcXfrsEoeEr1j2ybrGHrNgVsAhLgRgv6DaCszhMxAoGBALQW\nQ7GacEntUSZHH/OoQ/Lu2LzQ2gxNjrWKKZF2Q/WQNtMqTdR1qe0RxW+OCm11lYlH\nT2rDP3oT02SH4GUwEXa0kMwWvxkBXWlv/USLbtBZ44n1mW3pBScCt4XjXDrYFzHS\nYATZJD2yPu2DsVHv/zw24jRxW+Ejn4tgM6oRlOY3AoGAFKbGbnHHP39shBPWKi5A\nyQwy1pmgrShiptzHCghrRyT0zuXsOI/570DsdG8bbo2QolF5vtGVjJO1x8inDjGH\nhJMk0CS3IZYLctM1/H1gZMT50sAyyTEsTxcHmEXROfV0X9cLzmGxC592nCr6NRwz\nU0RWwhjG3bKfzRWTy2trtQs=\n-----END PRIVATE KEY-----"
  },
  {
    "path": "static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n\t\t<link\n\t\t\trel=\"stylesheet\"\n\t\t\thref=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css\"\n\t\t\tintegrity=\"sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ\"\n\t\t\tcrossorigin=\"anonymous\"\n\t\t/>\n\t\t<title>Nestjs SocketIO</title>\n\t\t<link rel=\"stylesheet\" href=\"styles.css\" />\n\t\t<script src=\"https://cdn.jsdelivr.net/npm/vue/dist/vue.js\"></script>\n\t\t<script\n\t\t\ttype=\"text/javascript\"\n\t\t\tsrc=\"https://cdn.socket.io/socket.io-1.4.5.js\"\n\t\t></script>\n\t</head>\n\t<body>\n\t\t<div id=\"app\" class=\"container\">\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col-md-6 offset-md-3 col-sm-12\">\n\t\t\t\t\t<h1 class=\"text-center\">{{ title }}</h1>\n\t\t\t\t\t<br />\n\t\t\t\t\t<div id=\"status\"></div>\n\t\t\t\t\t<div id=\"chat\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\tv-model=\"name\"\n\t\t\t\t\t\t\tid=\"username\"\n\t\t\t\t\t\t\tclass=\"form-control\"\n\t\t\t\t\t\t\tplaceholder=\"Enter name...\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<div class=\"card\">\n\t\t\t\t\t\t\t<div id=\"messages\" class=\"card-block\">\n\t\t\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t\t\t<li v-for=\"message of messages\">\n\t\t\t\t\t\t\t\t\t\t{{ message.name }}: {{ message.text }}\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<textarea\n\t\t\t\t\t\t\tid=\"textarea\"\n\t\t\t\t\t\t\tclass=\"form-control\"\n\t\t\t\t\t\t\tv-model=\"text\"\n\t\t\t\t\t\t\tplaceholder=\"Enter message...\"\n\t\t\t\t\t\t></textarea>\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<button id=\"send\" class=\"btn\" @click.prevent=\"sendMessage\">\n\t\t\t\t\t\t\tSend\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<script src=\"main.js\"></script>\n\t</body>\n</html>\n"
  },
  {
    "path": "static/main.js",
    "content": "const app = new Vue({\n\tel: '#app',\n\tdata: {\n\t\ttitle: 'Nestjs Websockets Chat',\n\t\tname: '',\n\t\ttext: '',\n\t\tmessages: [],\n\t\tsocket: null\n\t},\n\tmethods: {\n\t\tsendMessage() {\n\t\t\tif (this.validateInput()) {\n\t\t\t\tconst message = {\n\t\t\t\t\tname: this.name,\n\t\t\t\t\ttext: this.text\n\t\t\t\t}\n\t\t\t\tthis.socket.emit('msgToServer', message)\n\t\t\t\tthis.text = ''\n\t\t\t}\n\t\t},\n\t\treceivedMessage(message) {\n\t\t\tthis.messages.push(message)\n\t\t},\n\t\tvalidateInput() {\n\t\t\treturn this.name.length > 0 && this.text.length > 0\n\t\t}\n\t},\n\tcreated() {\n\t\tthis.socket = io('https://nestjs-restful-best-practice.herokuapp.com')\n\t\tthis.socket.on('msgToClient', message => {\n\t\t\tthis.receivedMessage(message)\n\t\t})\n\t}\n})\n"
  },
  {
    "path": "static/style.css",
    "content": "  #messages {\n    height: 300px;\n    overflow-y: scroll;\n  }\n\n  #app {\n    margin-top: 2rem;\n  }"
  },
  {
    "path": "test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "test/jest-e2e.json",
    "content": "{\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \".\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-spec.ts$\",\n  \"transform\": {\n    \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n  }\n}\n"
  },
  {
    "path": "tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./src\",\n    \"incremental\": true,\n    \"paths\": {\n      \"@auth\": [\"auth\"],\n      \"@common\": [\"common\"],\n      \"@config\": [\"config\"],\n      \"@environments\": [\"environments\"],\n      \"@models\": [\"models\"],\n      \"@shared\": [\"shared\"],\n      \"@utils\": [\"utils\"],\n      \"@validations\": [\"validations\"]\n    }\n  },\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n\t\"defaultSeverity\": \"error\",\n\t\"extends\": [\"tslint:recommended\"],\n\t\"jsRules\": {\n\t\t\"no-unused-expression\": true\n\t},\n\t\"rules\": {\n\t\t\"quotemark\": [true, \"single\"],\n\t\t\"member-access\": [false],\n\t\t\"ordered-imports\": [false],\n\t\t\"max-line-length\": [true, 150],\n\t\t\"member-ordering\": [false],\n\t\t\"interface-name\": [false],\n\t\t\"arrow-parens\": false,\n\t\t\"object-literal-sort-keys\": false,\n\n\t\t\"variable-name\": [true, \"allow-leading-underscore\"],\n\t\t\"indent\": false,\n\t\t\"trailing-comma\": false,\n\t\t\"semicolon\": false,\n\t\t\"no-bitwise\": false\n\t},\n\t\"rulesDirectory\": []\n}\n"
  },
  {
    "path": "webpack.config.js",
    "content": "const webpack = require('webpack')\nconst path = require('path')\nconst nodeExternals = require('webpack-node-externals')\nconst chalk = require('chalk')\nconst ProgressBarPlugin = require('progress-bar-webpack-plugin')\nconst BundleAnalyzerPlugin = require('webpack-bundle-analyzer')\n\t.BundleAnalyzerPlugin\n\nmodule.exports = {\n\tentry: ['webpack/hot/poll?100', './src/main.ts'],\n\twatch: true,\n\ttarget: 'node',\n\texternals: [\n\t\tnodeExternals({\n\t\t\twhitelist: ['webpack/hot/poll?100']\n\t\t})\n\t],\n\tmodule: {\n\t\trules: [\n\t\t\t{\n\t\t\t\ttest: /.tsx?$/,\n\t\t\t\tuse: 'ts-loader',\n\t\t\t\texclude: /node_modules/\n\t\t\t}\n\t\t]\n\t},\n\tmode: 'development',\n\tresolve: {\n\t\textensions: ['.tsx', '.ts', '.js']\n\t},\n\tplugins: [\n\t\tnew webpack.HotModuleReplacementPlugin(),\n\t\tnew webpack.WatchIgnorePlugin([/\\.js$/, /\\.d\\.ts$/]),\n\t\tnew ProgressBarPlugin({\n\t\t\tformat:\n\t\t\t\tchalk.hex('#6c5ce7')('build ') +\n\t\t\t\tchalk.hex('#0984e3')('▯:bar▯ ') +\n\t\t\t\t// chalk.red('▯ :bar ▯ ') +\n\t\t\t\tchalk.hex('#00b894')('(:percent) ') +\n\t\t\t\t// chalk.green(':percent ') +\n\t\t\t\tchalk.hex('#ffeaa7')(':msg'),\n\t\t\t// chalk.blue('( :elapsed s )')\n\t\t\tcomplete: '▰',\n\t\t\tincomplete: '▱',\n\t\t\tclear: false\n\t\t}),\n\t\tnew BundleAnalyzerPlugin({\n\t\t\tanalyzerMode: 'static',\n\t\t\tanalyzerHost: '127.0.0.1',\n\t\t\tanalyzerPort: '8888',\n\t\t\treportFilename: process.env.NODE_ENV === 'development' && 'report.html',\n\t\t\topenAnalyzer: false,\n\t\t\tgenerateStatsFile: false,\n\t\t\tstatsFilename: 'stats.json'\n\t\t}),\n\t\tnew webpack.BannerPlugin({\n\t\t\tbanner: 'require(\"source-map-support\").install();',\n\t\t\traw: true,\n\t\t\tentryOnly: false\n\t\t})\n\t],\n\toptimization: {\n\t\tremoveAvailableModules: false,\n\t\tremoveEmptyChunks: false,\n\t\tsplitChunks: false\n\t},\n\toutput: {\n\t\tpathinfo: false\n\t\t// path: path.join(__dirname, 'dist'),\n\t\t// filename: 'server.js'\n\t}\n}\n"
  }
]